Powershell computer class service automation





For several years now I have been working at the university to support 10 workstations running Microsoft Windows 8.1. Basically, the support consists in installing the software necessary for the educational process and ensuring overall performance.



Each station has 2 users: Administrator and Student. The administrator has full control, the Student does not have the ability to install the software. In order not to bother cleaning the Student user, this account is simply deleted entirely and created anew. This entails some body movements that must be performed at each station.



This year I decided to automate most of the body movements using PowerShell without ActiveDirectory and collected in this post some recipes that I found on the net.



Training



Immediately I came across the fact that PS 4 was installed at the stations and some examples from the omniscient Internet did not work. Therefore, before running the resulting scripts, you need to perform a couple of actions:



  1. Install Windows Management Framework 5.1
  2. Install the latest version of PowerShell


Automated actions



  1. Delete / create user account
  2. Auto login for a given user
  3. Running the script when the user first logs in


Delete / create user account



He started by creating. In this case, you need to perform 2 actions: create a user ( New-LocalUser ) and add it to the group ( Add-LocalGroupMember) . For convenience, I combined these commands into a function:



Function New-User {
    <#
    .SYNOPSIS
          
    .DESCRIPTION
                  
    .EXAMPLE
        #New-User "Student" "Student"
    .PARAMETER Name
           ( )
    .PARAMETER Password
         ( )
    #>

    [CmdletBinding()]
    param (
        [PARAMETER(Mandatory=$True)][String]$Name,
        [PARAMETER(Mandatory=$True)][String]$Password
        )

    $Pwd = convertto-securestring $Password -asplaintext -force
    $GroupSID = "S-1-5-32-545"
    New-LocalUser -User $Name -AccountNeverExpires:$true -FullName $Name -Password $Pwd -PasswordNeverExpires:$true
    Add-LocalGroupMember -SID $GroupSID -Member $Name

    Write-Host "--   $Name   $Password" -foregroundcolor Green
}


I add to the group by SID, because in one of the articles I met that the SID of the Users group is the same everywhere - S-1-5-32-545.



I organized the deletion according to the following principle: delete all accounts that were created by the Administrator. To do this, using the WMI object of the Win32_UserProfile class, I define all users who are not currently active and are not special.



Function Remove-Users {
    <#
    .SYNOPSIS
         
    .DESCRIPTION
           ,        
                
    .EXAMPLE
        #Remove-Users
    #>
    [CmdletBinding()]

    $UsersProfiles = Get-WMIObject -class Win32_UserProfile -ComputerName $env:COMPUTERNAME | Where {!($_.Loaded) -and !($_.Special)}
    foreach($Usr in $UsersProfiles) {
       	$UsrName = $Usr.LocalPath.Split("\")[2]
       	Write-Host "--   $UsrName ..." -foregroundcolor Green
       	Remove-LocalUser -Name $UsrName
	Remove-WmiObject -Path $Usr.__PATH
        Write-Host "--  $UsrName " -foregroundcolor Green
    }
}


Auto login (auto login) of the specified user



Everything here was limited to changing the HKEY_LOCAL_MACHINE registry. These actions are also combined into a small function:



Function Set-AutoLogon {
    <#
    .SYNOPSIS
           
    .DESCRIPTION
              
    .EXAMPLE
        #Set-AutoLogon  "Student" "Student"
    .PARAMETER Name
          ( )
    .PARAMETER Password
         ( )
    #>

    [CmdletBinding()]
    param (
        [PARAMETER(Mandatory=$True)][String]$Name,
        [PARAMETER(Mandatory=$True)][String]$Password
        )

    $PathToWinlogon = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"
    New-ItemProperty -Path $PathToWinlogon -Name AutoAdminLogon  -Value 1 -PropertyType "String"
    New-ItemProperty -Path $PathToWinlogon -Name DefaultUserName -Value $Name -PropertyType "String"
    New-ItemProperty -Path $PathToWinlogon -Name DefaultPassword -Value $Password -PropertyType "String"
}


Running the script when the user first logs in



It turned out that not everything can be configured before the first login of a new user (which was somewhat surprising to me). Therefore, there was a need to run a script that performs some actions after the first login:



  1. Proxy settings
  2. Prevent creating files on the desktop
  3. Customizing the User Control Panel


I tried several methods, but the following one turned out to be working for me: install the task. But I could not get the task by means of PS. So I took a long path:



schtasks /create /tn LogonUserSettings /tr "pwsh C:\Scripts\Settings.ps1" /sc onlogon /ru $env:USERDOMAIN\$UserName /rp $Password /f


But this was not enough - Windows asked for permission to log in as a batch job (SeBatchLogonRight). The search for an answer to the question of how to do this led to the following result :



LsaWrapper
$Source = @'
using System;
using System.Collections.Generic;
using System.Text;

namespace MyLsaWrapper
{
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Management;
    using System.Runtime.CompilerServices;
    using System.ComponentModel;

    using LSA_HANDLE = IntPtr;

    [StructLayout(LayoutKind.Sequential)]
    struct LSA_OBJECT_ATTRIBUTES
    {
        internal int Length;
        internal IntPtr RootDirectory;
        internal IntPtr ObjectName;
        internal int Attributes;
        internal IntPtr SecurityDescriptor;
        internal IntPtr SecurityQualityOfService;
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    struct LSA_UNICODE_STRING
    {
        internal ushort Length;
        internal ushort MaximumLength;
        [MarshalAs(UnmanagedType.LPWStr)]
        internal string Buffer;
    }
    sealed class Win32Sec
    {
        [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
        SuppressUnmanagedCodeSecurityAttribute]
        internal static extern uint LsaOpenPolicy(
        LSA_UNICODE_STRING[] SystemName,
        ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
        int AccessMask,
        out IntPtr PolicyHandle
        );

        [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
        SuppressUnmanagedCodeSecurityAttribute]
        internal static extern uint LsaAddAccountRights(
        LSA_HANDLE PolicyHandle,
        IntPtr pSID,
        LSA_UNICODE_STRING[] UserRights,
        int CountOfRights
        );

        [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
        SuppressUnmanagedCodeSecurityAttribute]
        internal static extern int LsaLookupNames2(
        LSA_HANDLE PolicyHandle,
        uint Flags,
        uint Count,
        LSA_UNICODE_STRING[] Names,
        ref IntPtr ReferencedDomains,
        ref IntPtr Sids
        );

        [DllImport("advapi32")]
        internal static extern int LsaNtStatusToWinError(int NTSTATUS);

        [DllImport("advapi32")]
        internal static extern int LsaClose(IntPtr PolicyHandle);

        [DllImport("advapi32")]
        internal static extern int LsaFreeMemory(IntPtr Buffer);

    }
    /// <summary>
    /// This class is used to grant "Log on as a service", "Log on as a batchjob", "Log on localy" etc.
    /// to a user.
    /// </summary>
    public sealed class LsaWrapper : IDisposable
    {
        [StructLayout(LayoutKind.Sequential)]
        struct LSA_TRUST_INFORMATION
        {
            internal LSA_UNICODE_STRING Name;
            internal IntPtr Sid;
        }
        [StructLayout(LayoutKind.Sequential)]
        struct LSA_TRANSLATED_SID2
        {
            internal SidNameUse Use;
            internal IntPtr Sid;
            internal int DomainIndex;
            uint Flags;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct LSA_REFERENCED_DOMAIN_LIST
        {
            internal uint Entries;
            internal LSA_TRUST_INFORMATION Domains;
        }

        enum SidNameUse : int
        {
            User = 1,
            Group = 2,
            Domain = 3,
            Alias = 4,
            KnownGroup = 5,
            DeletedAccount = 6,
            Invalid = 7,
            Unknown = 8,
            Computer = 9
        }

        enum Access : int
        {
            POLICY_READ = 0x20006,
            POLICY_ALL_ACCESS = 0x00F0FFF,
            POLICY_EXECUTE = 0X20801,
            POLICY_WRITE = 0X207F8
        }
        const uint STATUS_ACCESS_DENIED = 0xc0000022;
        const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a;
        const uint STATUS_NO_MEMORY = 0xc0000017;

        IntPtr lsaHandle;

        public LsaWrapper()
            : this(null)
        { }
        // // local system if systemName is null
        public LsaWrapper(string systemName)
        {
            LSA_OBJECT_ATTRIBUTES lsaAttr;
            lsaAttr.RootDirectory = IntPtr.Zero;
            lsaAttr.ObjectName = IntPtr.Zero;
            lsaAttr.Attributes = 0;
            lsaAttr.SecurityDescriptor = IntPtr.Zero;
            lsaAttr.SecurityQualityOfService = IntPtr.Zero;
            lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
            lsaHandle = IntPtr.Zero;
            LSA_UNICODE_STRING[] system = null;
            if (systemName != null)
            {
                system = new LSA_UNICODE_STRING[1];
                system[0] = InitLsaString(systemName);
            }

            uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr,
            (int)Access.POLICY_ALL_ACCESS, out lsaHandle);
            if (ret == 0)
                return;
            if (ret == STATUS_ACCESS_DENIED)
            {
                throw new UnauthorizedAccessException();
            }
            if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
            {
                throw new OutOfMemoryException();
            }
            throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
        }

        public void AddPrivileges(string account, string privilege)
        {
            IntPtr pSid = GetSIDInformation(account);
            LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
            privileges[0] = InitLsaString(privilege);
            uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1);
            if (ret == 0)
                return;
            if (ret == STATUS_ACCESS_DENIED)
            {
                throw new UnauthorizedAccessException();
            }
            if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
            {
                throw new OutOfMemoryException();
            }
            throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
        }

        public void Dispose()
        {
            if (lsaHandle != IntPtr.Zero)
            {
                Win32Sec.LsaClose(lsaHandle);
                lsaHandle = IntPtr.Zero;
            }
            GC.SuppressFinalize(this);
        }
        ~LsaWrapper()
        {
            Dispose();
        }
        // helper functions

        IntPtr GetSIDInformation(string account)
        {
            LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
            LSA_TRANSLATED_SID2 lts;
            IntPtr tsids = IntPtr.Zero;
            IntPtr tdom = IntPtr.Zero;
            names[0] = InitLsaString(account);
            lts.Sid = IntPtr.Zero;
            //Console.WriteLine("String account: {0}", names[0].Length);
            int ret = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids);
            if (ret != 0)
                throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret));
            lts = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(tsids,
            typeof(LSA_TRANSLATED_SID2));
            Win32Sec.LsaFreeMemory(tsids);
            Win32Sec.LsaFreeMemory(tdom);
            return lts.Sid;
        }

        static LSA_UNICODE_STRING InitLsaString(string s)
        {
            // Unicode strings max. 32KB
            if (s.Length > 0x7ffe)
                throw new ArgumentException("String too long");
            LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
            lus.Buffer = s;
            lus.Length = (ushort)(s.Length * sizeof(char));
            lus.MaximumLength = (ushort)(lus.Length + sizeof(char));
            return lus;
        }
    }
    public class LsaWrapperCaller
    {
        public static void AddPrivileges(string account, string privilege)
        {
            using (LsaWrapper lsaWrapper = new LsaWrapper())
            {
                lsaWrapper.AddPrivileges(account, privilege);
            }
        }
    }
}
'@

Add-Type -TypeDefinition $Source
[MyLsaWrapper.LsaWrapperCaller]::AddPrivileges($Identity, "SeBatchLogonRight")




Allowing logins as a batch job allowed us to move on to writing a script that runs from under the user.



Proxy settings



With the proxy setting, everything turned out to be simple. A working solution was quickly found:



Function Set-Proxy {
    <#
    .SYNOPSIS
          
    .DESCRIPTION
              
    .EXAMPLE
        #Set-Proxy a.cproxy.ru 8080
    .PARAMETER Server
             ( )
    .PARAMETER Port
         ( )
    #>

    [CmdletBinding()]
    param (
        [PARAMETER(Mandatory=$True)][String]$Server,
        [PARAMETER(Mandatory=$True)][Int]$Port
        )

    If ((Test-NetConnection -ComputerName $Server -Port $Port).TcpTestSucceeded) {
        Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name ProxyServer -Value "$($Server):$($Port)"
        Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name ProxyEnable -Value 1
    } Else {
        Write-Error -Message "-- Invalid proxy server address or port:  $($Server):$($Port)"
    }
}


Prevent creating files on the desktop



The prohibition of creating files on the desktop took longer to tinker with than the network. Setting the rights to the folder was not there just like in * nix systems. But even here there were answers that I successfully adapted for myself:



Function Set-AccessRule {
    <#
    .SYNOPSIS
           
    .DESCRIPTION
              
    .EXAMPLE
        #Set-AccessRule -Folder $env:USERPROFILE\Desktop\  -UserName $env:USERNAME -Rules CreateFiles,AppendData -AccessControlType Deny
    .PARAMETER Folder
        ,     ( )
    .PARAMETER UserName
           ,      ( )
    .PARAMETER Rules
            ( )
    .PARAMETER AccessControlType
         ,       : Allow  Deny
    #>
    [CmdletBinding()]
    param (
        [PARAMETER(Mandatory=$True)][Path]$Folder,
        [PARAMETER(Mandatory=$True)][String]$UserName,
        [PARAMETER(Mandatory=$True)][String]$Rules,
        [PARAMETER(Mandatory=$True)][String]$AccessControlType
        )

    #   ACL  
    $acl = Get-Acl $Folder
    #    
    $fileSystemRights = [System.Security.AccessControl.FileSystemRights]"$Rules"
    #C    ,     
    $AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($UserName, $fileSystemRights, $AccessControlType)
    #    FileSystemAccessRule   
    $acl.SetAccessRule($AccessRule)
    #   
    $acl | Set-Acl $Folder
}

Set-AccessRule -Folder $env:USERPROFILE\Desktop\  -UserName $env:USERNAME -Rules CreateFiles,AppendData,Delete -AccessControlType Deny


Description of FileSystemRights on the official website .



Customizing the User Control Panel



This was optional, but I thought it would be cool to provide students with a custom dashboard with commonly used programs. The answer was found here .



PinnedApplication
function Set-PinnedApplication
{
    <#
    .SYNOPSIS
            
    .DESCRIPTION
                 
    .EXAMPLE
        #Set-PinnedApplication -Action UnpinfromTaskbar -FilePath "$env:ProgramFiles\Internet Explorer\iexplore.exe"
    .EXAMPLE
        #Set-PinnedApplication -Action PintoTaskbar -FilePath "${env:ProgramFiles(x86)}\Mozilla Firefox\firefox.exe"
    .PARAMETER Action
         ,       : UnpinfromTaskbar  PintoTaskbar
    .PARAMETER FilePath
           ,      ( )
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$True)][String]$Action, 
        [Parameter(Mandatory=$True)][String]$FilePath
   	)
    if(-not (test-path $FilePath)) { 
   	throw "FilePath does not exist."  
    }
    function InvokeVerb {
   	param([string]$FilePath,$verb)
	$verb = $verb.Replace("&","")
	$path = split-path $FilePath
	$shell = new-object -com "Shell.Application" 
	$folder = $shell.Namespace($path)   
	$item = $folder.Parsename((split-path $FilePath -leaf))
	$itemVerb = $item.Verbs() | ? {$_.Name.Replace("&","") -eq $verb}
	if($itemVerb -eq $null){
		throw "Verb $verb not found."			
	} else {
		$itemVerb.DoIt()
	}
   }
    function GetVerb {
	param([int]$verbId)
	try {
		$t = [type]"CosmosKey.Util.MuiHelper"
	} catch {
	    $def = [Text.StringBuilder]""
	    [void]$def.AppendLine('[DllImport("user32.dll")]')
	    [void]$def.AppendLine('public static extern int LoadString(IntPtr h,uint id, System.Text.StringBuilder sb,int maxBuffer);')
	    [void]$def.AppendLine('[DllImport("kernel32.dll")]')
	    [void]$def.AppendLine('public static extern IntPtr LoadLibrary(string s);')
	    Add-Type -MemberDefinition $def.ToString() -name MuiHelper -namespace CosmosKey.Util			
	}
	if($global:CosmosKey_Utils_MuiHelper_Shell32 -eq $null){		
	    $global:CosmosKey_Utils_MuiHelper_Shell32 = [CosmosKey.Util.MuiHelper]::LoadLibrary("shell32.dll")
	}
	$maxVerbLength=255
	$verbBuilder = New-Object Text.StringBuilder "",$maxVerbLength
	[void][CosmosKey.Util.MuiHelper]::LoadString($CosmosKey_Utils_MuiHelper_Shell32,$verbId,$verbBuilder,$maxVerbLength)
	return $verbBuilder.ToString()
    }
    $verbs = @{ 
	"PintoTaskbar"=5386
	"UnpinfromTaskbar"=5387
    }
    if($verbs.$Action -eq $null){
   	Throw "Action $action not supported`nSupported actions are:`n`tPintoTaskbar`n`tUnpinfromTaskbar"
    }
    InvokeVerb -FilePath $FilePath -Verb $(GetVerb -VerbId $verbs.$action)
}




Conclusion



The scripts work, the service time for each station has been reduced, the goal has been achieved. For me, as a Linux user, setting up Windows turned out to be not the easiest adventure, but educational. I will develop the setup script. There are plans to add a check for installed software and installation, launching an antivirus.



Final scripts in work



Function New-User {
    <#
    .SYNOPSIS
          
    .DESCRIPTION
                  
    .EXAMPLE
        #New-User "Student" "Student"
    .PARAMETER Name
           ( )
    .PARAMETER Password
         ( )
    #>

    [CmdletBinding()]
    param (
        [PARAMETER(Mandatory=$True)][String]$Name,
        [PARAMETER(Mandatory=$True)][String]$Password
        )

    $Pwd = convertto-securestring $Password -asplaintext -force
    $GroupSID = "S-1-5-32-545"
    New-LocalUser -User $Name -AccountNeverExpires:$true -FullName $Name -Password $Pwd -PasswordNeverExpires:$true
    Add-LocalGroupMember -SID $GroupSID -Member $Name

    Write-Host "--   $Name   $Password" -foregroundcolor Green
}

Function Remove-Users {
    <#
    .SYNOPSIS
         
    .DESCRIPTION
           ,        
                
    .EXAMPLE
        #Remove-Users
    #>
    [CmdletBinding()]

    $UsersProfiles = Get-WMIObject -class Win32_UserProfile -ComputerName $env:COMPUTERNAME | Where {!($_.Loaded) -and !($_.Special)}
	foreach($Usr in $UsersProfiles) {
        $UsrName = $Usr.LocalPath.Split("\")[2]
        Write-Host "--   $UsrName ..." -foregroundcolor Green
        Remove-LocalUser -Name $UsrName
		Remove-WmiObject -Path $Usr.__PATH
        Write-Host "--  $UsrName " -foregroundcolor Green
	}
}

Function Set-AutoLogon {
    <#
    .SYNOPSIS
           
    .DESCRIPTION
              
    .EXAMPLE
        #Set-AutoLogon  "Student" "Student"
    .PARAMETER Name
          ( )
    .PARAMETER Password
         ( )
    #>

    [CmdletBinding()]
    param (
        [PARAMETER(Mandatory=$True)][String]$Name,
        [PARAMETER(Mandatory=$True)][String]$Password
        )

    $PathToWinlogon = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"
    New-ItemProperty -Path $PathToWinlogon -Name AutoAdminLogon  -Value 1 -PropertyType "String"
    New-ItemProperty -Path $PathToWinlogon -Name DefaultUserName -Value $Name -PropertyType "String"
    New-ItemProperty -Path $PathToWinlogon -Name DefaultPassword -Value $Password -PropertyType "String"
}

$Source = @'
using System;
using System.Collections.Generic;
using System.Text;

namespace MyLsaWrapper
{
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Management;
    using System.Runtime.CompilerServices;
    using System.ComponentModel;

    using LSA_HANDLE = IntPtr;

    [StructLayout(LayoutKind.Sequential)]
    struct LSA_OBJECT_ATTRIBUTES
    {
        internal int Length;
        internal IntPtr RootDirectory;
        internal IntPtr ObjectName;
        internal int Attributes;
        internal IntPtr SecurityDescriptor;
        internal IntPtr SecurityQualityOfService;
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    struct LSA_UNICODE_STRING
    {
        internal ushort Length;
        internal ushort MaximumLength;
        [MarshalAs(UnmanagedType.LPWStr)]
        internal string Buffer;
    }
    sealed class Win32Sec
    {
        [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
        SuppressUnmanagedCodeSecurityAttribute]
        internal static extern uint LsaOpenPolicy(
        LSA_UNICODE_STRING[] SystemName,
        ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
        int AccessMask,
        out IntPtr PolicyHandle
        );

        [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
        SuppressUnmanagedCodeSecurityAttribute]
        internal static extern uint LsaAddAccountRights(
        LSA_HANDLE PolicyHandle,
        IntPtr pSID,
        LSA_UNICODE_STRING[] UserRights,
        int CountOfRights
        );

        [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
        SuppressUnmanagedCodeSecurityAttribute]
        internal static extern int LsaLookupNames2(
        LSA_HANDLE PolicyHandle,
        uint Flags,
        uint Count,
        LSA_UNICODE_STRING[] Names,
        ref IntPtr ReferencedDomains,
        ref IntPtr Sids
        );

        [DllImport("advapi32")]
        internal static extern int LsaNtStatusToWinError(int NTSTATUS);

        [DllImport("advapi32")]
        internal static extern int LsaClose(IntPtr PolicyHandle);

        [DllImport("advapi32")]
        internal static extern int LsaFreeMemory(IntPtr Buffer);

    }
    /// <summary>
    /// This class is used to grant "Log on as a service", "Log on as a batchjob", "Log on localy" etc.
    /// to a user.
    /// </summary>
    public sealed class LsaWrapper : IDisposable
    {
        [StructLayout(LayoutKind.Sequential)]
        struct LSA_TRUST_INFORMATION
        {
            internal LSA_UNICODE_STRING Name;
            internal IntPtr Sid;
        }
        [StructLayout(LayoutKind.Sequential)]
        struct LSA_TRANSLATED_SID2
        {
            internal SidNameUse Use;
            internal IntPtr Sid;
            internal int DomainIndex;
            uint Flags;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct LSA_REFERENCED_DOMAIN_LIST
        {
            internal uint Entries;
            internal LSA_TRUST_INFORMATION Domains;
        }

        enum SidNameUse : int
        {
            User = 1,
            Group = 2,
            Domain = 3,
            Alias = 4,
            KnownGroup = 5,
            DeletedAccount = 6,
            Invalid = 7,
            Unknown = 8,
            Computer = 9
        }

        enum Access : int
        {
            POLICY_READ = 0x20006,
            POLICY_ALL_ACCESS = 0x00F0FFF,
            POLICY_EXECUTE = 0X20801,
            POLICY_WRITE = 0X207F8
        }
        const uint STATUS_ACCESS_DENIED = 0xc0000022;
        const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a;
        const uint STATUS_NO_MEMORY = 0xc0000017;

        IntPtr lsaHandle;

        public LsaWrapper()
            : this(null)
        { }
        // // local system if systemName is null
        public LsaWrapper(string systemName)
        {
            LSA_OBJECT_ATTRIBUTES lsaAttr;
            lsaAttr.RootDirectory = IntPtr.Zero;
            lsaAttr.ObjectName = IntPtr.Zero;
            lsaAttr.Attributes = 0;
            lsaAttr.SecurityDescriptor = IntPtr.Zero;
            lsaAttr.SecurityQualityOfService = IntPtr.Zero;
            lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
            lsaHandle = IntPtr.Zero;
            LSA_UNICODE_STRING[] system = null;
            if (systemName != null)
            {
                system = new LSA_UNICODE_STRING[1];
                system[0] = InitLsaString(systemName);
            }

            uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr,
            (int)Access.POLICY_ALL_ACCESS, out lsaHandle);
            if (ret == 0)
                return;
            if (ret == STATUS_ACCESS_DENIED)
            {
                throw new UnauthorizedAccessException();
            }
            if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
            {
                throw new OutOfMemoryException();
            }
            throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
        }

        public void AddPrivileges(string account, string privilege)
        {
            IntPtr pSid = GetSIDInformation(account);
            LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
            privileges[0] = InitLsaString(privilege);
            uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1);
            if (ret == 0)
                return;
            if (ret == STATUS_ACCESS_DENIED)
            {
                throw new UnauthorizedAccessException();
            }
            if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
            {
                throw new OutOfMemoryException();
            }
            throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
        }

        public void Dispose()
        {
            if (lsaHandle != IntPtr.Zero)
            {
                Win32Sec.LsaClose(lsaHandle);
                lsaHandle = IntPtr.Zero;
            }
            GC.SuppressFinalize(this);
        }
        ~LsaWrapper()
        {
            Dispose();
        }
        // helper functions

        IntPtr GetSIDInformation(string account)
        {
            LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
            LSA_TRANSLATED_SID2 lts;
            IntPtr tsids = IntPtr.Zero;
            IntPtr tdom = IntPtr.Zero;
            names[0] = InitLsaString(account);
            lts.Sid = IntPtr.Zero;
            //Console.WriteLine("String account: {0}", names[0].Length);
            int ret = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids);
            if (ret != 0)
                throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret));
            lts = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(tsids,
            typeof(LSA_TRANSLATED_SID2));
            Win32Sec.LsaFreeMemory(tsids);
            Win32Sec.LsaFreeMemory(tdom);
            return lts.Sid;
        }

        static LSA_UNICODE_STRING InitLsaString(string s)
        {
            // Unicode strings max. 32KB
            if (s.Length > 0x7ffe)
                throw new ArgumentException("String too long");
            LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
            lus.Buffer = s;
            lus.Length = (ushort)(s.Length * sizeof(char));
            lus.MaximumLength = (ushort)(lus.Length + sizeof(char));
            return lus;
        }
    }
    public class LsaWrapperCaller
    {
        public static void AddPrivileges(string account, string privilege)
        {
            using (LsaWrapper lsaWrapper = new LsaWrapper())
            {
                lsaWrapper.AddPrivileges(account, privilege);
            }
        }
    }
}
'@

Add-Type -TypeDefinition $Source | Out-Null


# -------------------------
#  
# -------------------------
$UserName    = "Student"
$Password    = "Student"

Remove-Users | Out-Null
New-User $UserName $Password | Out-Null
Set-AutoLogon $UserName $Password | Out-Null
[MyLsaWrapper.LsaWrapperCaller]::AddPrivileges($UserName, "SeBatchLogonRight") | Out-Null
write-host "--         $UserName" -foregroundcolor Green
schtasks /create /tn LogonUserSettings /tr "pwsh C:\Scripts\SetupUser.ps1" /sc onlogon /ru $env:USERDOMAIN\$UserName /rp $Password /f


- Student



Function Set-Proxy {
    <#
    .SYNOPSIS
          
    .DESCRIPTION
              
    .EXAMPLE
        #Set-Proxy a.cproxy.ru 8080
    .PARAMETER Server
             ( )
    .PARAMETER Port
         ( )
    #>

    [CmdletBinding()]
    param (
        [PARAMETER(Mandatory=$True)][String]$Server,
        [PARAMETER(Mandatory=$True)][Int]$Port
        )

	If ((Test-NetConnection -ComputerName $Server -Port $Port).TcpTestSucceeded) {
		Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name ProxyServer -Value "$($Server):$($Port)"
		Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name ProxyEnable -Value 1
	} Else {
		Write-Error -Message "-- Invalid proxy server address or port:  $($Server):$($Port)"
	}
}

Function Set-AccessRule {
    <#
    .SYNOPSIS
           
    .DESCRIPTION
              
    .EXAMPLE
        #Set-AccessRule -Folder $env:USERPROFILE\Desktop\  -UserName $env:USERNAME -Rules CreateFiles,AppendData -AccessControlType Deny
    .PARAMETER Folder
        ,     ( )
    .PARAMETER UserName
           ,      ( )
    .PARAMETER Rules
           ( )
    .PARAMETER AccessControlType
         ,       : Allow  Deny
    #>
    [CmdletBinding()]
    param (
        [PARAMETER(Mandatory=$True)][String]$Folder,
        [PARAMETER(Mandatory=$True)][String]$UserName,
        [PARAMETER(Mandatory=$True)][String]$Rules,
        [PARAMETER(Mandatory=$True)][String]$AccessControlType
        )

    #   ACL  
    $acl = Get-Acl $Folder
    #    
    $fileSystemRights = [System.Security.AccessControl.FileSystemRights]"$Rules"
    #C    ,     
    $AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($UserName, $fileSystemRights, $AccessControlType)
    #    FileSystemAccessRule   
    $acl.SetAccessRule($AccessRule)
    #   
    $acl | Set-Acl $Folder
}

function Set-PinnedApplication
{
    <#
    .SYNOPSIS
            
    .DESCRIPTION
                 
    .EXAMPLE
        #Set-PinnedApplication -Action UnpinfromTaskbar -FilePath "$env:ProgramFiles\Internet Explorer\iexplore.exe"
    .EXAMPLE
        #Set-PinnedApplication -Action PintoTaskbar -FilePath "${env:ProgramFiles(x86)}\Mozilla Firefox\firefox.exe"
    .PARAMETER Action
         ,       : UnpinfromTaskbar  PintoTaskbar
    .PARAMETER FilePath
           ,      ( )
    #>
    [CmdletBinding()]
    param(
            [Parameter(Mandatory=$True)][String]$Action, 
            [Parameter(Mandatory=$True)][String]$FilePath
    )
    if(-not (test-path $FilePath)) { 
        throw "FilePath does not exist."  
    }
    function InvokeVerb {
        param([string]$FilePath,$verb)
        $verb = $verb.Replace("&","")
        $path = split-path $FilePath
        $shell = new-object -com "Shell.Application" 
        $folder = $shell.Namespace($path)   
        $item = $folder.Parsename((split-path $FilePath -leaf))
        $itemVerb = $item.Verbs() | ? {$_.Name.Replace("&","") -eq $verb}
        if($itemVerb -eq $null){
            throw "Verb $verb not found."           
        } else {
            $itemVerb.DoIt()
        }
    }
    function GetVerb {
        param([int]$verbId)
        try {
            $t = [type]"CosmosKey.Util.MuiHelper"
        } catch {
            $def = [Text.StringBuilder]""
            [void]$def.AppendLine('[DllImport("user32.dll")]')
            [void]$def.AppendLine('public static extern int LoadString(IntPtr h,uint id, System.Text.StringBuilder sb,int maxBuffer);')
            [void]$def.AppendLine('[DllImport("kernel32.dll")]')
            [void]$def.AppendLine('public static extern IntPtr LoadLibrary(string s);')
            Add-Type -MemberDefinition $def.ToString() -name MuiHelper -namespace CosmosKey.Util            
        }
        if($global:CosmosKey_Utils_MuiHelper_Shell32 -eq $null){        
            $global:CosmosKey_Utils_MuiHelper_Shell32 = [CosmosKey.Util.MuiHelper]::LoadLibrary("shell32.dll")
        }
        $maxVerbLength=255
        $verbBuilder = New-Object Text.StringBuilder "",$maxVerbLength
        [void][CosmosKey.Util.MuiHelper]::LoadString($CosmosKey_Utils_MuiHelper_Shell32,$verbId,$verbBuilder,$maxVerbLength)
        return $verbBuilder.ToString()
    }
    $verbs = @{ 
        "PintoTaskbar"=5386
        "UnpinfromTaskbar"=5387
    }
    if($verbs.$Action -eq $null){
        Throw "Action $action not supported`nSupported actions are:`n`tPintoTaskbar`n`tUnpinfromTaskbar"
    }
    InvokeVerb -FilePath $FilePath -Verb $(GetVerb -VerbId $verbs.$action)
}

Set-Proxy cproxy.udsu.ru 8080
Set-AccessRule -Folder $env:USERPROFILE\Desktop\  -UserName $env:USERNAME -Rules "CreateFiles,AppendData,Delete" -AccessControlType Deny

Set-PinnedApplication -Action UnpinfromTaskbar -FilePath "$env:ProgramFiles\Internet Explorer\iexplore.exe"
Set-PinnedApplication -Action PintoTaskbar -FilePath "${env:ProgramFiles(x86)}\Mozilla Firefox\firefox.exe"
Set-PinnedApplication -Action PintoTaskbar -FilePath "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Office 2013\Excel 2013.lnk"
Set-PinnedApplication -Action PintoTaskbar -FilePath "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Office 2013\Word 2013.lnk"
Set-PinnedApplication -Action PintoTaskbar -FilePath "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Office 2013\PowerPoint 2013.lnk"
Set-PinnedApplication -Action PintoTaskbar -FilePath "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\\-3D V16\-3D V16.lnk"

#  ,   
Unregister-ScheduledTask -TaskName UdSUSettingStudent -Confirm:$false





All Articles