Repository: saltstack/salt
Pull request: [3006.x] Fix state for User policy
### What does this PR do?
Fixes `lgpo_reg` state to work with User policy

### What issues does this PR fix or reference?
Fixes: #64200 

### Merge requirements satisfied?
**[NOTICE] Bug fixes or features added to Salt require tests.**
<!-- Please review the [test documentation](https://docs.saltproject.io/en/master/topics/tutorials/writing_tests.html) for details on how to implement tests into Salt's test suite. -->
- [ ] Docs
- [x] Changelog - https://docs.saltproject.io/en/master/topics/development/changelog.html
- [x] Tests written/updated

### Commits signed with GPG?
Yes

Problem statement:
[BUG] lgpo_reg state doesn't work with User policy
**Description**
The lgpo_reg state doesn't work when specifying the User policy class

**Setup**
Given the following state (mystate.sls):
```
set_reg_pol_value:
  lgpo_reg.value_present:
    - key: SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced
    - name: HideFileExt
    - v_data: 0
    - v_type: REG_DWORD
    - policy_class: User
```

**Steps to Reproduce the behavior**
Apply the state:
```
salt-call --local state.apply mystate
```

**Expected behavior**
The state should apply successfully

**Screenshots**
```
salt-call --local state.apply mystate
local:
----------
          ID: set_reg_pol_value
    Function: lgpo_reg.value_present
        Name: HideFileExt
      Result: False
     Comment: An exception occurred in this state: Traceback (most recent call last):
                File "C:\Program Files\Salt Project\Salt\lib\site-packages\salt\state.py", line 2385, in call
                  ret = self.states[cdata["full"]](
                File "C:\Program Files\Salt Project\Salt\lib\site-packages\salt\loader\lazy.py", line 149, in __call__
                  return self.loader.run(run_func, *args, **kwargs)
                File "C:\Program Files\Salt Project\Salt\lib\site-packages\salt\loader\lazy.py", line 1232, in run
                  return self._last_context.run(self._run_as, _func_or_method, *args, **kwargs)
                File "C:\Program Files\Salt Project\Salt\lib\site-packages\salt\loader\lazy.py", line 1247, in _run_as
                  return _func_or_method(*args, **kwargs)
                File "C:\Program Files\Salt Project\Salt\lib\site-packages\salt\loader\lazy.py", line 1280, in wrapper
                  return f(*args, **kwargs)
                File "C:\Program Files\Salt Project\Salt\Lib\site-packages\salt\states\win_lgpo_reg.py", line 156, in value_present
                  if str(new["data"]) == v_data and new["type"] == v_type:
              KeyError: 'data'
     Started: 21:14:58.686519
    Duration: 101.512 ms
     Changes:

Summary for local
------------
Succeeded: 0
Failed:    1
------------
Total states run:     1
Total run time: 101.512 ms
```

**Versions Report**
<details><summary>salt --versions-report</summary>
(Provided by running salt --versions-report. Please also mention any differences in master/minion versions.)

```yaml
3006.0
and head of 3006.x
```
</details>

Hints from issue discussion:

Commit message: Fix pre-commit

Patch to review:
diff --git a/changelog/64200.fixed.md b/changelog/64200.fixed.md
new file mode 100644
index 000000000000..9c977309cb97
--- /dev/null
+++ b/changelog/64200.fixed.md
@@ -0,0 +1 @@
+Fix ``lgpo_reg`` state to work with User policy
diff --git a/salt/modules/win_lgpo_reg.py b/salt/modules/win_lgpo_reg.py
index 4052de62bd3d..2fd04bd3c737 100644
--- a/salt/modules/win_lgpo_reg.py
+++ b/salt/modules/win_lgpo_reg.py
@@ -381,7 +381,7 @@ def set_value(
     else:
         pol_data[key] = {v_name: {"data": v_data, "type": v_type}}
 
-    write_reg_pol(pol_data)
+    write_reg_pol(pol_data, policy_class=policy_class)
 
     return salt.utils.win_reg.set_value(
         hive=hive,
@@ -464,7 +464,7 @@ def disable_value(key, v_name, policy_class="machine"):
     else:
         pol_data[key] = {"**del.{}".format(v_name): {"data": " ", "type": "REG_SZ"}}
 
-    write_reg_pol(pol_data)
+    write_reg_pol(pol_data, policy_class=policy_class)
 
     return salt.utils.win_reg.delete_value(hive=hive, key=key, vname=v_name)
 
@@ -534,7 +534,7 @@ def delete_value(key, v_name, policy_class="Machine"):
     else:
         return None
 
-    write_reg_pol(pol_data)
+    write_reg_pol(pol_data, policy_class=policy_class)
 
     return salt.utils.win_reg.delete_value(hive=hive, key=key, vname=v_name)
 
diff --git a/salt/states/win_lgpo_reg.py b/salt/states/win_lgpo_reg.py
index 7a514068acb8..23120c6fe049 100644
--- a/salt/states/win_lgpo_reg.py
+++ b/salt/states/win_lgpo_reg.py
@@ -153,7 +153,7 @@ def value_present(name, key, v_data, v_type="REG_DWORD", policy_class="Machine")
         key=key, v_name=name, policy_class=policy_class
     )
 
-    if str(new["data"]) == v_data and new["type"] == v_type:
+    if str(new["data"]) == str(v_data) and new["type"] == v_type:
         ret["comment"] = "Registry.pol value has been set"
         ret["result"] = True
     else:
diff --git a/tests/pytests/unit/modules/test_win_lgpo_reg.py b/tests/pytests/unit/modules/test_win_lgpo_reg.py
index 6d4a824b308b..b2bd351018ba 100644
--- a/tests/pytests/unit/modules/test_win_lgpo_reg.py
+++ b/tests/pytests/unit/modules/test_win_lgpo_reg.py
@@ -30,7 +30,7 @@ def configure_loader_modules():
 
 
 @pytest.fixture
-def empty_reg_pol():
+def empty_reg_pol_mach():
     class_info = salt.utils.win_lgpo_reg.CLASS_INFO
     reg_pol_file = pathlib.Path(class_info["Machine"]["policy_path"])
     if not reg_pol_file.parent.exists():
@@ -47,7 +47,24 @@ def empty_reg_pol():
 
 
 @pytest.fixture
-def reg_pol():
+def empty_reg_pol_user():
+    class_info = salt.utils.win_lgpo_reg.CLASS_INFO
+    reg_pol_file = pathlib.Path(class_info["User"]["policy_path"])
+    if not reg_pol_file.parent.exists():
+        reg_pol_file.parent.mkdir(parents=True)
+    with salt.utils.files.fopen(str(reg_pol_file), "wb") as f:
+        f.write(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
+    salt.utils.win_reg.delete_key_recursive(hive="HKLM", key="SOFTWARE\\MyKey1")
+    salt.utils.win_reg.delete_key_recursive(hive="HKLM", key="SOFTWARE\\MyKey2")
+    yield
+    salt.utils.win_reg.delete_key_recursive(hive="HKLM", key="SOFTWARE\\MyKey1")
+    salt.utils.win_reg.delete_key_recursive(hive="HKLM", key="SOFTWARE\\MyKey2")
+    with salt.utils.files.fopen(str(reg_pol_file), "wb") as f:
+        f.write(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
+
+
+@pytest.fixture
+def reg_pol_mach():
     data_to_write = {
         "SOFTWARE\\MyKey1": {
             "MyValue1": {
@@ -90,17 +107,151 @@ def reg_pol():
         f.write(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
 
 
-def test_read_reg_pol(empty_reg_pol):
-    expected = {}
-    result = lgpo_reg.read_reg_pol()
-    assert result == expected
+@pytest.fixture
+def reg_pol_user():
+    data_to_write = {
+        "SOFTWARE\\MyKey1": {
+            "MyValue1": {
+                "data": "squidward",
+                "type": "REG_SZ",
+            },
+            "**del.MyValue2": {
+                "data": " ",
+                "type": "REG_SZ",
+            },
+        },
+        "SOFTWARE\\MyKey2": {
+            "MyValue3": {
+                "data": ["spongebob", "squarepants"],
+                "type": "REG_MULTI_SZ",
+            },
+        },
+    }
+    lgpo_reg.write_reg_pol(data_to_write, policy_class="User")
+    salt.utils.win_reg.set_value(
+        hive="HKCU",
+        key="SOFTWARE\\MyKey1",
+        vname="MyValue1",
+        vdata="squidward",
+        vtype="REG_SZ",
+    )
+    salt.utils.win_reg.set_value(
+        hive="HKCU",
+        key="SOFTWARE\\MyKey2",
+        vname="MyValue3",
+        vdata=["spongebob", "squarepants"],
+        vtype="REG_MULTI_SZ",
+    )
+    yield
+    salt.utils.win_reg.delete_key_recursive(hive="HKCU", key="SOFTWARE\\MyKey1")
+    salt.utils.win_reg.delete_key_recursive(hive="HKCU", key="SOFTWARE\\MyKey2")
+    class_info = salt.utils.win_lgpo_reg.CLASS_INFO
+    reg_pol_file = class_info["User"]["policy_path"]
+    with salt.utils.files.fopen(reg_pol_file, "wb") as f:
+        f.write(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
+
+
+def test_invalid_policy_class_delete_value():
+    pytest.raises(
+        SaltInvocationError,
+        lgpo_reg.delete_value,
+        key="",
+        v_name="",
+        policy_class="Invalid",
+    )
+
+
+def test_invalid_policy_class_disable_value():
+    pytest.raises(
+        SaltInvocationError,
+        lgpo_reg.disable_value,
+        key="",
+        v_name="",
+        policy_class="Invalid",
+    )
+
+
+def test_invalid_policy_class_get_key():
+    pytest.raises(SaltInvocationError, lgpo_reg.get_key, key="", policy_class="Invalid")
+
+
+def test_invalid_policy_class_get_value():
+    pytest.raises(
+        SaltInvocationError,
+        lgpo_reg.get_value,
+        key="",
+        v_name="",
+        policy_class="Invalid",
+    )
 
 
-def test_read_reg_pol_invalid_policy_class():
+def test_invalid_policy_class_read_reg_pol():
     pytest.raises(SaltInvocationError, lgpo_reg.read_reg_pol, policy_class="Invalid")
 
 
-def test_write_reg_pol(empty_reg_pol):
+def test_invalid_policy_class_set_value():
+    pytest.raises(
+        SaltInvocationError,
+        lgpo_reg.set_value,
+        key="",
+        v_name="",
+        v_data="",
+        policy_class="Invalid",
+    )
+
+
+def test_invalid_policy_class_write_reg_pol():
+    pytest.raises(
+        SaltInvocationError, lgpo_reg.write_reg_pol, data={}, policy_class="Invalid"
+    )
+
+
+def test_set_value_invalid_reg_type():
+    pytest.raises(
+        SaltInvocationError,
+        lgpo_reg.set_value,
+        key="",
+        v_name="",
+        v_data="",
+        v_type="REG_INVALID",
+    )
+
+
+def test_set_value_invalid_reg_sz():
+    pytest.raises(
+        SaltInvocationError,
+        lgpo_reg.set_value,
+        key="",
+        v_name="",
+        v_data=[],
+        v_type="REG_SZ",
+    )
+
+
+def test_set_value_invalid_reg_multi_sz():
+    pytest.raises(
+        SaltInvocationError,
+        lgpo_reg.set_value,
+        key="",
+        v_name="",
+        v_data=1,
+        v_type="REG_MULTI_SZ",
+    )
+
+
+def test_set_value_invalid_reg_dword():
+    pytest.raises(
+        SaltInvocationError, lgpo_reg.set_value, key="", v_name="", v_data="string"
+    )
+
+
+def test_mach_read_reg_pol(empty_reg_pol_mach):
+    expected = {}
+    result = lgpo_reg.read_reg_pol()
+    assert result == expected
+
+
+def test_mach_write_reg_pol(empty_reg_pol_mach):
     data_to_write = {
         r"SOFTWARE\MyKey": {
             "MyValue": {
@@ -114,29 +265,13 @@ def test_write_reg_pol(empty_reg_pol):
     assert result == data_to_write
 
 
-def test_write_reg_pol_invalid_policy_class():
-    pytest.raises(
-        SaltInvocationError, lgpo_reg.write_reg_pol, data={}, policy_class="Invalid"
-    )
-
-
-def test_get_value(reg_pol):
+def test_mach_get_value(reg_pol_mach):
     expected = {"data": "squidward", "type": "REG_SZ"}
     result = lgpo_reg.get_value(key="SOFTWARE\\MyKey1", v_name="MyValue1")
     assert result == expected
 
 
-def test_get_value_invalid_policy_class():
-    pytest.raises(
-        SaltInvocationError,
-        lgpo_reg.get_value,
-        key="",
-        v_name="",
-        policy_class="Invalid",
-    )
-
-
-def test_get_key(reg_pol):
+def test_mach_get_key(reg_pol_mach):
     expected = {
         "MyValue3": {
             "data": ["spongebob", "squarepants"],
@@ -147,11 +282,7 @@ def test_get_key(reg_pol):
     assert result == expected
 
 
-def test_get_key_invalid_policy_class():
-    pytest.raises(SaltInvocationError, lgpo_reg.get_key, key="", policy_class="Invalid")
-
-
-def test_set_value(empty_reg_pol):
+def test_mach_set_value(empty_reg_pol_mach):
     key = "SOFTWARE\\MyKey"
     v_name = "MyValue"
     # Test command return
@@ -174,7 +305,7 @@ def test_set_value(empty_reg_pol):
     assert result == expected
 
 
-def test_set_value_existing_change(reg_pol):
+def test_mach_set_value_existing_change(reg_pol_mach):
     expected = {"data": 1, "type": "REG_DWORD"}
     key = "SOFTWARE\\MyKey"
     v_name = "MyValue1"
@@ -193,7 +324,7 @@ def test_set_value_existing_change(reg_pol):
     assert result == expected
 
 
-def test_set_value_existing_no_change(reg_pol):
+def test_mach_set_value_existing_no_change(reg_pol_mach):
     expected = {"data": "squidward", "type": "REG_SZ"}
     key = "SOFTWARE\\MyKey"
     v_name = "MyValue1"
@@ -202,57 +333,7 @@ def test_set_value_existing_no_change(reg_pol):
     assert result == expected
 
 
-def test_set_value_invalid_policy_class():
-    pytest.raises(
-        SaltInvocationError,
-        lgpo_reg.set_value,
-        key="",
-        v_name="",
-        v_data="",
-        policy_class="Invalid",
-    )
-
-
-def test_set_value_invalid_reg_type():
-    pytest.raises(
-        SaltInvocationError,
-        lgpo_reg.set_value,
-        key="",
-        v_name="",
-        v_data="",
-        v_type="REG_INVALID",
-    )
-
-
-def test_set_value_invalid_reg_sz():
-    pytest.raises(
-        SaltInvocationError,
-        lgpo_reg.set_value,
-        key="",
-        v_name="",
-        v_data=[],
-        v_type="REG_SZ",
-    )
-
-
-def test_set_value_invalid_reg_multi_sz():
-    pytest.raises(
-        SaltInvocationError,
-        lgpo_reg.set_value,
-        key="",
-        v_name="",
-        v_data=1,
-        v_type="REG_MULTI_SZ",
-    )
-
-
-def test_set_value_invalid_reg_dword():
-    pytest.raises(
-        SaltInvocationError, lgpo_reg.set_value, key="", v_name="", v_data="string"
-    )
-
-
-def test_disable_value(reg_pol):
+def test_mach_disable_value(reg_pol_mach):
     key = "SOFTWARE\\MyKey1"
     # Test that the command completed successfully
     result = lgpo_reg.disable_value(key=key, v_name="MyValue1")
@@ -269,7 +350,7 @@ def test_disable_value(reg_pol):
     assert result is False
 
 
-def test_disable_value_no_change(reg_pol):
+def test_mach_disable_value_no_change(reg_pol_mach):
     expected = {
         "MyValue1": {"data": "squidward", "type": "REG_SZ"},
         "**del.MyValue2": {"data": " ", "type": "REG_SZ"},
@@ -280,17 +361,7 @@ def test_disable_value_no_change(reg_pol):
     assert result == expected
 
 
-def test_disable_value_invalid_policy_class():
-    pytest.raises(
-        SaltInvocationError,
-        lgpo_reg.disable_value,
-        key="",
-        v_name="",
-        policy_class="Invalid",
-    )
-
-
-def test_delete_value_existing(reg_pol):
+def test_mach_delete_value_existing(reg_pol_mach):
     key = "SOFTWARE\\MyKey1"
     # Test that the command completes successfully
     result = lgpo_reg.delete_value(key=key, v_name="MyValue1")
@@ -309,7 +380,7 @@ def test_delete_value_existing(reg_pol):
     assert result is False
 
 
-def test_delete_value_no_change(empty_reg_pol):
+def test_mach_delete_value_no_change(empty_reg_pol_mach):
     expected = {}
     key = "SOFTWARE\\MyKey1"
     lgpo_reg.delete_value(key=key, v_name="MyValue2")
@@ -317,11 +388,159 @@ def test_delete_value_no_change(empty_reg_pol):
     assert result == expected
 
 
-def test_delete_value_invalid_policy_class():
-    pytest.raises(
-        SaltInvocationError,
-        lgpo_reg.delete_value,
-        key="",
-        v_name="",
-        policy_class="Invalid",
+def test_user_read_reg_pol(empty_reg_pol_user):
+    expected = {}
+    result = lgpo_reg.read_reg_pol(policy_class="User")
+    assert result == expected
+
+
+def test_user_write_reg_pol(empty_reg_pol_user):
+    data_to_write = {
+        r"SOFTWARE\MyKey": {
+            "MyValue": {
+                "data": "string",
+                "type": "REG_SZ",
+            },
+        },
+    }
+    lgpo_reg.write_reg_pol(data_to_write, policy_class="User")
+    result = lgpo_reg.read_reg_pol(policy_class="User")
+    assert result == data_to_write
+
+
+def test_user_get_value(reg_pol_user):
+    expected = {"data": "squidward", "type": "REG_SZ"}
+    result = lgpo_reg.get_value(
+        key="SOFTWARE\\MyKey1",
+        v_name="MyValue1",
+        policy_class="User",
+    )
+    assert result == expected
+
+
+def test_user_get_key(reg_pol_user):
+    expected = {
+        "MyValue3": {
+            "data": ["spongebob", "squarepants"],
+            "type": "REG_MULTI_SZ",
+        },
+    }
+    result = lgpo_reg.get_key(key="SOFTWARE\\MyKey2", policy_class="User")
+    assert result == expected
+
+
+def test_user_set_value(empty_reg_pol_user):
+    key = "SOFTWARE\\MyKey"
+    v_name = "MyValue"
+    # Test command return
+    result = lgpo_reg.set_value(
+        key=key,
+        v_name=v_name,
+        v_data="1",
+        policy_class="User",
+    )
+    assert result is True
+    # Test value actually set in Registry.pol
+    expected = {"data": 1, "type": "REG_DWORD"}
+    result = lgpo_reg.get_value(key=key, v_name=v_name, policy_class="User")
+    assert result == expected
+    # Test that the registry value has been set
+    expected = {
+        "hive": "HKCU",
+        "key": key,
+        "vname": v_name,
+        "vdata": 1,
+        "vtype": "REG_DWORD",
+        "success": True,
+    }
+    result = salt.utils.win_reg.read_value(hive="HKCU", key=key, vname=v_name)
+    assert result == expected
+
+
+def test_user_set_value_existing_change(reg_pol_user):
+    expected = {"data": 1, "type": "REG_DWORD"}
+    key = "SOFTWARE\\MyKey"
+    v_name = "MyValue1"
+    lgpo_reg.set_value(key=key, v_name=v_name, v_data="1", policy_class="User")
+    result = lgpo_reg.get_value(key=key, v_name=v_name, policy_class="User")
+    assert result == expected
+    expected = {
+        "hive": "HKCU",
+        "key": key,
+        "vname": v_name,
+        "vdata": 1,
+        "vtype": "REG_DWORD",
+        "success": True,
+    }
+    result = salt.utils.win_reg.read_value(hive="HKCU", key=key, vname=v_name)
+    assert result == expected
+
+
+def test_user_set_value_existing_no_change(reg_pol_user):
+    expected = {"data": "squidward", "type": "REG_SZ"}
+    key = "SOFTWARE\\MyKey"
+    v_name = "MyValue1"
+    lgpo_reg.set_value(
+        key=key,
+        v_name=v_name,
+        v_data="squidward",
+        v_type="REG_SZ",
+        policy_class="User",
     )
+    result = lgpo_reg.get_value(key=key, v_name=v_name, policy_class="User")
+    assert result == expected
+
+
+def test_user_disable_value(reg_pol_user):
+    key = "SOFTWARE\\MyKey1"
+    # Test that the command completed successfully
+    result = lgpo_reg.disable_value(key=key, v_name="MyValue1", policy_class="User")
+    assert result is True
+    # Test that the value was actually set in Registry.pol
+    expected = {
+        "**del.MyValue1": {"data": " ", "type": "REG_SZ"},
+        "**del.MyValue2": {"data": " ", "type": "REG_SZ"},
+    }
+    result = lgpo_reg.get_key(key=key, policy_class="User")
+    assert result == expected
+    # Test that the registry value has been removed
+    result = salt.utils.win_reg.value_exists(hive="HKCU", key=key, vname="MyValue1")
+    assert result is False
+
+
+def test_user_disable_value_no_change(reg_pol_user):
+    expected = {
+        "MyValue1": {"data": "squidward", "type": "REG_SZ"},
+        "**del.MyValue2": {"data": " ", "type": "REG_SZ"},
+    }
+    key = "SOFTWARE\\MyKey1"
+    lgpo_reg.disable_value(key=key, v_name="MyValue2", policy_class="User")
+    result = lgpo_reg.get_key(key=key, policy_class="User")
+    assert result == expected
+
+
+def test_user_delete_value_existing(reg_pol_user):
+    key = "SOFTWARE\\MyKey1"
+    # Test that the command completes successfully
+    result = lgpo_reg.delete_value(key=key, v_name="MyValue1", policy_class="User")
+    assert result is True
+    # Test that the value is actually removed from Registry.pol
+    expected = {
+        "**del.MyValue2": {
+            "data": " ",
+            "type": "REG_SZ",
+        },
+    }
+    result = lgpo_reg.get_key(key=key, policy_class="User")
+    assert result == expected
+    # Test that the registry entry has been removed
+    result = salt.utils.win_reg.value_exists(hive="HKCU", key=key, vname="MyValue2")
+    assert result is False
+
+
+def test_user_delete_value_no_change(empty_reg_pol_user):
+    expected = {}
+    key = "SOFTWARE\\MyKey1"
+    lgpo_reg.delete_value(key=key, v_name="MyValue2", policy_class="User")
+    result = lgpo_reg.get_key(key=key, policy_class="User")
+    assert result == expected
diff --git a/tests/pytests/unit/states/test_win_lgpo_reg.py b/tests/pytests/unit/states/test_win_lgpo_reg.py
index d2ca5cc74337..181cfa1c888a 100644
--- a/tests/pytests/unit/states/test_win_lgpo_reg.py
+++ b/tests/pytests/unit/states/test_win_lgpo_reg.py
@@ -1,9 +1,15 @@
+import os
+import pathlib
+
 import pytest
 
+import salt.modules.win_file as file
 import salt.modules.win_lgpo_reg as win_lgpo_reg
 import salt.states.win_lgpo_reg as lgpo_reg
 import salt.utils.files
+import salt.utils.win_dacl
 import salt.utils.win_lgpo_reg
+import salt.utils.win_reg
 from tests.support.mock import patch
 
 pytestmark = [
@@ -25,22 +31,40 @@ def configure_loader_modules():
                 "lgpo_reg.delete_value": win_lgpo_reg.delete_value,
             },
         },
+        file: {
+            "__utils__": {
+                "dacl.set_perms": salt.utils.win_dacl.set_perms,
+            },
+        },
     }
 
 
 @pytest.fixture
-def empty_reg_pol():
+def empty_reg_pol_mach():
     class_info = salt.utils.win_lgpo_reg.CLASS_INFO
-    reg_pol_file = class_info["Machine"]["policy_path"]
-    with salt.utils.files.fopen(reg_pol_file, "wb") as f:
-        f.write(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
+    reg_pol_file = pathlib.Path(class_info["Machine"]["policy_path"])
+    reg_pol_file.parent.mkdir(parents=True, exist_ok=True)
+    reg_pol_file.write_bytes(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
     yield
-    with salt.utils.files.fopen(reg_pol_file, "wb") as f:
-        f.write(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
+    salt.utils.win_reg.delete_key_recursive(hive="HKLM", key="SOFTWARE\\MyKey1")
+    salt.utils.win_reg.delete_key_recursive(hive="HKLM", key="SOFTWARE\\MyKey2")
+    reg_pol_file.write_bytes(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
 
 
 @pytest.fixture
-def reg_pol():
+def empty_reg_pol_user():
+    class_info = salt.utils.win_lgpo_reg.CLASS_INFO
+    reg_pol_file = pathlib.Path(class_info["User"]["policy_path"])
+    reg_pol_file.parent.mkdir(parents=True, exist_ok=True)
+    reg_pol_file.write_bytes(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
+    yield
+    salt.utils.win_reg.delete_key_recursive(hive="HKCU", key="SOFTWARE\\MyKey1")
+    salt.utils.win_reg.delete_key_recursive(hive="HKCU", key="SOFTWARE\\MyKey2")
+    reg_pol_file.write_bytes(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
+
+
+@pytest.fixture
+def reg_pol_mach():
     data_to_write = {
         r"SOFTWARE\MyKey1": {
             "MyValue1": {
@@ -51,6 +75,10 @@ def reg_pol():
                 "data": " ",
                 "type": "REG_SZ",
             },
+            "MyValue3": {
+                "data": 0,
+                "type": "REG_DWORD",
+            },
         },
         r"SOFTWARE\MyKey2": {
             "MyValue3": {
@@ -61,19 +89,55 @@ def reg_pol():
     }
     win_lgpo_reg.write_reg_pol(data_to_write)
     yield
+    salt.utils.win_reg.delete_key_recursive(hive="HKLM", key="SOFTWARE\\MyKey1")
+    salt.utils.win_reg.delete_key_recursive(hive="HKLM", key="SOFTWARE\\MyKey2")
     class_info = salt.utils.win_lgpo_reg.CLASS_INFO
     reg_pol_file = class_info["Machine"]["policy_path"]
     with salt.utils.files.fopen(reg_pol_file, "wb") as f:
         f.write(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
 
 
+@pytest.fixture
+def reg_pol_user():
+    data_to_write = {
+        r"SOFTWARE\MyKey1": {
+            "MyValue1": {
+                "data": "squidward",
+                "type": "REG_SZ",
+            },
+            "**del.MyValue2": {
+                "data": " ",
+                "type": "REG_SZ",
+            },
+            "MyValue3": {
+                "data": 0,
+                "type": "REG_DWORD",
+            },
+        },
+        r"SOFTWARE\MyKey2": {
+            "MyValue3": {
+                "data": ["spongebob", "squarepants"],
+                "type": "REG_MULTI_SZ",
+            },
+        },
+    }
+    win_lgpo_reg.write_reg_pol(data_to_write, policy_class="User")
+    yield
+    salt.utils.win_reg.delete_key_recursive(hive="HKCU", key="SOFTWARE\\MyKey1")
+    salt.utils.win_reg.delete_key_recursive(hive="HKCU", key="SOFTWARE\\MyKey2")
+    class_info = salt.utils.win_lgpo_reg.CLASS_INFO
+    reg_pol_file = class_info["User"]["policy_path"]
+    with salt.utils.files.fopen(reg_pol_file, "wb") as f:
+        f.write(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
+
+
 def test_virtual_name():
     assert lgpo_reg.__virtual__() == "lgpo_reg"
 
 
-def test_value_present(empty_reg_pol):
+def test_machine_value_present(empty_reg_pol_mach):
     """
-    Test value.present
+    Test value.present in Machine policy
     """
     result = lgpo_reg.value_present(
         name="MyValue",
@@ -96,9 +160,9 @@ def test_value_present(empty_reg_pol):
     assert result == expected
 
 
-def test_value_present_existing_change(reg_pol):
+def test_machine_value_present_existing_change(reg_pol_mach):
     """
-    Test value.present with existing incorrect value
+    Test value.present with existing incorrect value in Machine policy
     """
     result = lgpo_reg.value_present(
         name="MyValue1",
@@ -124,9 +188,35 @@ def test_value_present_existing_change(reg_pol):
     assert result == expected
 
 
-def test_value_present_existing_no_change(reg_pol):
+def test_machine_value_present_existing_change_dword(reg_pol_mach):
+    """
+    Test value.present with existing incorrect value in Machine policy
+    """
+    result = lgpo_reg.value_present(
+        name="MyValue3",
+        key="SOFTWARE\\MyKey1",
+        v_data=1,
+        v_type="REG_DWORD",
+    )
+    expected = {
+        "changes": {
+            "new": {
+                "data": 1,
+            },
+            "old": {
+                "data": 0,
+            },
+        },
+        "comment": "Registry.pol value has been set",
+        "name": "MyValue3",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_machine_value_present_existing_no_change(reg_pol_mach):
     """
-    Test value.present with existing correct value
+    Test value.present with existing correct value in Machine policy
     """
     result = lgpo_reg.value_present(
         name="MyValue1",
@@ -143,9 +233,9 @@ def test_value_present_existing_no_change(reg_pol):
     assert result == expected
 
 
-def test_value_present_test_true(empty_reg_pol):
+def test_machine_value_present_test_true(empty_reg_pol_mach):
     """
-    Test value.present with test=True
+    Test value.present with test=True in Machine policy
     """
     with patch.dict(lgpo_reg.__opts__, {"test": True}):
         result = lgpo_reg.value_present(
@@ -163,9 +253,9 @@ def test_value_present_test_true(empty_reg_pol):
     assert result == expected
 
 
-def test_value_present_existing_disabled(reg_pol):
+def test_machine_value_present_existing_disabled(reg_pol_mach):
     """
-    Test value.present with existing value that is disabled
+    Test value.present with existing value that is disabled in Machine policy
     """
     result = lgpo_reg.value_present(
         name="MyValue2",
@@ -191,9 +281,9 @@ def test_value_present_existing_disabled(reg_pol):
     assert result == expected
 
 
-def test_value_disabled(empty_reg_pol):
+def test_machine_value_disabled(empty_reg_pol_mach):
     """
-    Test value.disabled
+    Test value.disabled in Machine policy
     """
     result = lgpo_reg.value_disabled(
         name="MyValue1",
@@ -214,9 +304,10 @@ def test_value_disabled(empty_reg_pol):
     assert result == expected
 
 
-def test_value_disabled_existing_change(reg_pol):
+def test_machine_value_disabled_existing_change(reg_pol_mach):
     """
-    Test value.disabled with an existing value that is not disabled
+    Test value.disabled with an existing value that is not disabled in Machine
+    policy
     """
     result = lgpo_reg.value_disabled(
         name="MyValue1",
@@ -238,9 +329,9 @@ def test_value_disabled_existing_change(reg_pol):
     assert result == expected
 
 
-def test_value_disabled_existing_no_change(reg_pol):
+def test_machine_value_disabled_existing_no_change(reg_pol_mach):
     """
-    Test value.disabled with an existing disabled value
+    Test value.disabled with an existing disabled value in Machine policy
     """
     result = lgpo_reg.value_disabled(
         name="MyValue2",
@@ -255,9 +346,9 @@ def test_value_disabled_existing_no_change(reg_pol):
     assert result == expected
 
 
-def test_value_disabled_test_true(empty_reg_pol):
+def test_machine_value_disabled_test_true(empty_reg_pol_mach):
     """
-    Test value.disabled when test=True
+    Test value.disabled when test=True in Machine policy
     """
     with patch.dict(lgpo_reg.__opts__, {"test": True}):
         result = lgpo_reg.value_disabled(
@@ -273,9 +364,9 @@ def test_value_disabled_test_true(empty_reg_pol):
     assert result == expected
 
 
-def test_value_absent(reg_pol):
+def test_machine_value_absent(reg_pol_mach):
     """
-    Test value.absent
+    Test value.absent in Machine policy
     """
     result = lgpo_reg.value_absent(name="MyValue1", key="SOFTWARE\\MyKey1")
     expected = {
@@ -293,9 +384,9 @@ def test_value_absent(reg_pol):
     assert result == expected
 
 
-def test_value_absent_no_change(empty_reg_pol):
+def test_machine_value_absent_no_change(empty_reg_pol_mach):
     """
-    Test value.absent when the value is already absent
+    Test value.absent when the value is already absent in Machine policy
     """
     result = lgpo_reg.value_absent(name="MyValue1", key="SOFTWARE\\MyKey1")
     expected = {
@@ -307,9 +398,9 @@ def test_value_absent_no_change(empty_reg_pol):
     assert result == expected
 
 
-def test_value_absent_disabled(reg_pol):
+def test_machine_value_absent_disabled(reg_pol_mach):
     """
-    Test value.absent when the value is disabled
+    Test value.absent when the value is disabled in Machine policy
     """
     result = lgpo_reg.value_absent(name="MyValue2", key="SOFTWARE\\MyKey1")
     expected = {
@@ -327,9 +418,9 @@ def test_value_absent_disabled(reg_pol):
     assert result == expected
 
 
-def test_value_absent_test_true(reg_pol):
+def test_machine_value_absent_test_true(reg_pol_mach):
     """
-    Test value.absent with test=True
+    Test value.absent with test=True in Machine policy
     """
     with patch.dict(lgpo_reg.__opts__, {"test": True}):
         result = lgpo_reg.value_absent(name="MyValue1", key="SOFTWARE\\MyKey1")
@@ -340,3 +431,325 @@ def test_value_absent_test_true(reg_pol):
         "result": None,
     }
     assert result == expected
+
+
+def test_user_value_present(empty_reg_pol_user):
+    """
+    Test value.present in User policy
+    """
+    result = lgpo_reg.value_present(
+        name="MyValue",
+        key="SOFTWARE\\MyKey",
+        v_data="1",
+        v_type="REG_DWORD",
+        policy_class="User",
+    )
+    expected = {
+        "changes": {
+            "new": {
+                "data": 1,
+                "type": "REG_DWORD",
+            },
+            "old": {},
+        },
+        "comment": "Registry.pol value has been set",
+        "name": "MyValue",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_user_value_present_existing_change(reg_pol_user):
+    """
+    Test value.present with existing incorrect value in User policy
+    """
+    result = lgpo_reg.value_present(
+        name="MyValue1",
+        key="SOFTWARE\\MyKey1",
+        v_data="2",
+        v_type="REG_DWORD",
+        policy_class="User",
+    )
+    expected = {
+        "changes": {
+            "new": {
+                "data": 2,
+                "type": "REG_DWORD",
+            },
+            "old": {
+                "data": "squidward",
+                "type": "REG_SZ",
+            },
+        },
+        "comment": "Registry.pol value has been set",
+        "name": "MyValue1",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_user_value_present_existing_change_dword(reg_pol_user):
+    """
+    Test value.present with existing incorrect value in User policy
+    """
+    result = lgpo_reg.value_present(
+        name="MyValue3",
+        key="SOFTWARE\\MyKey1",
+        v_data=1,
+        v_type="REG_DWORD",
+        policy_class="User",
+    )
+    expected = {
+        "changes": {
+            "new": {
+                "data": 1,
+            },
+            "old": {
+                "data": 0,
+            },
+        },
+        "comment": "Registry.pol value has been set",
+        "name": "MyValue3",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_user_value_present_existing_no_change(reg_pol_user):
+    """
+    Test value.present with existing correct value in User policy
+    """
+    result = lgpo_reg.value_present(
+        name="MyValue1",
+        key="SOFTWARE\\MyKey1",
+        v_data="squidward",
+        v_type="REG_SZ",
+        policy_class="User",
+    )
+    expected = {
+        "changes": {},
+        "comment": "Registry.pol value already present",
+        "name": "MyValue1",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_user_value_present_test_true(empty_reg_pol_user):
+    """
+    Test value.present with test=True in User policy
+    """
+    with patch.dict(lgpo_reg.__opts__, {"test": True}):
+        result = lgpo_reg.value_present(
+            name="MyValue",
+            key="SOFTWARE\\MyKey",
+            v_data="1",
+            v_type="REG_DWORD",
+            policy_class="User",
+        )
+    expected = {
+        "changes": {},
+        "comment": "Registry.pol value will be set",
+        "name": "MyValue",
+        "result": None,
+    }
+    assert result == expected
+
+
+def test_user_value_present_existing_disabled(reg_pol_user):
+    """
+    Test value.present with existing value that is disabled in User policy
+    """
+    result = lgpo_reg.value_present(
+        name="MyValue2",
+        key="SOFTWARE\\MyKey1",
+        v_data="2",
+        v_type="REG_DWORD",
+        policy_class="User",
+    )
+    expected = {
+        "changes": {
+            "new": {
+                "data": 2,
+                "type": "REG_DWORD",
+            },
+            "old": {
+                "data": "**del.MyValue2",
+                "type": "REG_SZ",
+            },
+        },
+        "comment": "Registry.pol value has been set",
+        "name": "MyValue2",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_user_value_disabled(empty_reg_pol_user):
+    """
+    Test value.disabled in User policy
+    """
+    result = lgpo_reg.value_disabled(
+        name="MyValue1", key="SOFTWARE\\MyKey1", policy_class="User"
+    )
+    expected = {
+        "changes": {
+            "new": {
+                "data": "**del.MyValue1",
+                "type": "REG_SZ",
+            },
+            "old": {},
+        },
+        "comment": "Registry.pol value disabled",
+        "name": "MyValue1",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_user_value_disabled_existing_change(reg_pol_user):
+    """
+    Test value.disabled with an existing value that is not disabled in User
+    policy
+    """
+    result = lgpo_reg.value_disabled(
+        name="MyValue1",
+        key="SOFTWARE\\MyKey1",
+        policy_class="User",
+    )
+    expected = {
+        "changes": {
+            "new": {
+                "data": "**del.MyValue1",
+            },
+            "old": {
+                "data": "squidward",
+            },
+        },
+        "comment": "Registry.pol value disabled",
+        "name": "MyValue1",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_user_value_disabled_existing_no_change(reg_pol_user):
+    """
+    Test value.disabled with an existing disabled value in User policy
+    """
+    result = lgpo_reg.value_disabled(
+        name="MyValue2",
+        key="SOFTWARE\\MyKey1",
+        policy_class="User",
+    )
+    expected = {
+        "changes": {},
+        "comment": "Registry.pol value already disabled",
+        "name": "MyValue2",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_user_value_disabled_test_true(empty_reg_pol_user):
+    """
+    Test value.disabled when test=True in User policy
+    """
+    with patch.dict(lgpo_reg.__opts__, {"test": True}):
+        result = lgpo_reg.value_disabled(
+            name="MyValue",
+            key="SOFTWARE\\MyKey",
+            policy_class="User",
+        )
+    expected = {
+        "changes": {},
+        "comment": "Registry.pol value will be disabled",
+        "name": "MyValue",
+        "result": None,
+    }
+    assert result == expected
+
+
+def test_user_value_absent(reg_pol_user):
+    """
+    Test value.absent in User policy
+    """
+    result = lgpo_reg.value_absent(
+        name="MyValue1",
+        key="SOFTWARE\\MyKey1",
+        policy_class="User",
+    )
+    expected = {
+        "changes": {
+            "new": {},
+            "old": {
+                "data": "squidward",
+                "type": "REG_SZ",
+            },
+        },
+        "comment": "Registry.pol value deleted",
+        "name": "MyValue1",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_user_value_absent_no_change(empty_reg_pol_user):
+    """
+    Test value.absent when the value is already absent in User policy
+    """
+    result = lgpo_reg.value_absent(
+        name="MyValue1",
+        key="SOFTWARE\\MyKey1",
+        policy_class="User",
+    )
+    expected = {
+        "changes": {},
+        "comment": "Registry.pol value already absent",
+        "name": "MyValue1",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_user_value_absent_disabled(reg_pol_user):
+    """
+    Test value.absent when the value is disabled in User policy
+    """
+    result = lgpo_reg.value_absent(
+        name="MyValue2",
+        key="SOFTWARE\\MyKey1",
+        policy_class="User",
+    )
+    expected = {
+        "changes": {
+            "new": {},
+            "old": {
+                "data": "**del.MyValue2",
+                "type": "REG_SZ",
+            },
+        },
+        "comment": "Registry.pol value deleted",
+        "name": "MyValue2",
+        "result": True,
+    }
+    assert result == expected
+
+
+def test_user_value_absent_test_true(reg_pol_user):
+    """
+    Test value.absent with test=True in User policy
+    """
+    with patch.dict(lgpo_reg.__opts__, {"test": True}):
+        result = lgpo_reg.value_absent(
+            name="MyValue1",
+            key="SOFTWARE\\MyKey1",
+            policy_class="User",
+        )
+    expected = {
+        "changes": {},
+        "comment": "Registry.pol value will be deleted",
+        "name": "MyValue1",
+        "result": None,
+    }
+    assert result == expected


Code review comments:
diff_hunk: @@ -47,7 +47,24 @@ def empty_reg_pol():
 
 
 @pytest.fixture
-def reg_pol():
+def empty_reg_pol_user():
+    class_info = salt.utils.win_lgpo_reg.CLASS_INFO
+    reg_pol_file = pathlib.Path(class_info["User"]["policy_path"])
+    if not reg_pol_file.parent.exists():
+        reg_pol_file.parent.mkdir(parents=True)
+    with salt.utils.files.fopen(str(reg_pol_file), "wb") as f:
+        f.write(salt.utils.win_lgpo_reg.REG_POL_HEADER.encode("utf-16-le"))
+    salt.utils.win_reg.delete_key_recursive(hive="HKLM", key="SOFTWARE\\MyKey1")
path: tests/pytests/unit/modules/test_win_lgpo_reg.py
text: @user1:
Shouldn't this be HKCU considering function name suggests its the user hive.

Maybe I'm missing something as I'm not familiar with the codebase, just making sure its not a typo!