oxygen.psm1
Set-StrictMode -Version Latest Function Test-TcpConnection { <# .SYNOPSIS Tests connection to a port on a computer. .DESCRIPTION Tests connection to a port on a computer by attempting to open and then close it. This function is superceded in PowerShell v5+ by Test-NetConnection and has been kept for backwards compatibility. .EXAMPLE Test-TcpConnection -Server 'myserver' -Port '123' Tests if a connection can be established to port '123' on 'myserver'. .EXAMPLE Test-TcpConnection -Server 'server01', 'server02' -Port '80', '443' Tests if a connection can be established to ports 80 and 443 on server01 and server02. .INPUTS None .OUTPUTS [boolean] .NOTES Author : Unknown - Refactored by Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : 1.0 - 21/04/18 - Initial release .LINK https://github.com/pauby/oxygen/blob/master/docs/test-tcpconnection.md #> [CmdletBinding()] [OutputType([boolean])] param ( [Parameter(Mandatory, Position = 0)] [ValidateNotNullOrEmpty()] [string[]] $Server, [Parameter(Mandatory, Position = 1)] [ValidateRange(0, 65535)] [int[]] $Port, [Parameter(Position = 2)] [int] $TimeOut = 2 ) $timeoutMs = $TimeOut * 1000 ForEach ($s in $Server) { ForEach ($p in $Port) { $ip = [System.Net.Dns]::GetHostAddresses($s) $address = [System.Net.IPAddress]::Parse($ip[0]) $socket = New-Object System.Net.Sockets.TCPClient Write-Verbose "Connecting to '$address' on port '$p'" try { $connect = $socket.BeginConnect($address, $p, $null, $null) } catch { Write-Warning "'$s' is not responding on port '$p'" return $false } Start-Sleep -Seconds $TimeOut if ($connect.IsCompleted) { $wait = $connect.AsyncWaitHandle.WaitOne($timeoutMs, $false) if (!$wait) { $socket.Close() Write-Warning "'$s' is not responding on port '$p'" return $false } else { try { $socket.EndConnect($connect) Write-Verbose "'$s' is responding on port '$p'" return $true } catch { Write-Warning "'$s' is not responding on port '$p'" } $socket.Close() return $false } } else { Write-Warning "'$s' is not responding on port '$p'" return $false } } #end ForEach $Port } #end ForEach $Server } function Reset-Printer { <# .SYNOPSIS Reset the specified printer on the local computer. .DESCRIPTION Reset the specified printer on the local computer by removing the printer, driver and port and adding them back. .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : v1.0 - 20 April 2014 .INPUTS None .OUTPUTS [boolean] .EXAMPLE Reset-Printer -Name "HP LaserJet 4" -DriverName "HP LaserJet PS" -PortName "HPLJ4" -PrinterHostAddress "192.168.10.100" Resets the printer called "HP LaserJet 4", driver named "HP LaserJet PS", port "HPLJ4" with IP address 192.168.10.100 by removing the port, driver and printer and then adding them back again. .LINK Reset-PrinterDriver .LINK Reset-PrinterPort .LINK Test-Printer .LINK Test-PrinterDriver .LINK Test-PrinterDriverStore .LINK Test-PrinterPort .LINK https://github.com/pauby/oxygen/blob/master/docs/reset-printer.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact='Low')] [OutputType([boolean])] Param ( # Specifies the name of the printer to reset on the local computer. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateScript( { Test-Printer -Name $_ } )] [string]$Name, # Specifies the name of the driver to reset on the local computer. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateScript( { Test-PrinterDriver -Name $_ } )] [string]$DriverName, # Specifies the name of the port to reset on the local computer. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateScript( { Test-PrinterPort -Name $_ } )] [string]$PortName, # Specifies the IP address of the printer to reset on the local computer. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateScript( { Test-Connection -ComputerName $_ -Count 1 -Quiet } )] [IPAddress]$IPAddress, # Force the removal [Switch]$Force ) Begin { if (-not $PSBoundParameters.ContainsKey('Confirm')) { $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') } if (-not $PSBoundParameters.ContainsKey('WhatIf')) { $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') } } Process { Write-Verbose "Removing printer $Name" if ($PSCmdlet.ShouldProcess($Name, "Removing printer")) { Remove-Printer -Name $Name } Write-Verbose "Checking printer $Name has been removed" if (Test-Printer -Name $Name) { $false } else { # check each of these suceeds. if ((-not (Reset-PrinterPort -PortName $PortName -IPAddress $IPAddress)) -or (-not (Reset-PrinterDriver -DriverName $DriverName)) -or (-not (Add-Printer -Name $Name -DriverName $DriverName -PortName $PortName -Force:($Force.IsPresent))) ) { $false } else { $true } } } End { } } function Reset-PrinterDriver { <# .SYNOPSIS Reset the specified printer driver. .DESCRIPTION Reset the specified printer driver by removing it and adding it back again. .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : v1.0 - 20 April 2018 .INPUTS None .OUTPUTS [boolean] .EXAMPLE Reset-PrinterDriver -Name "HP LaserJet PS" Remove and add the printer driver called "HP LaserJet PS" .LINK Reset-Printer .LINK Reset-PrinterPort .LINK Test-Printer .LINK Test-PrinterDriver .LINK Test-PrinterDriverStore .LINK Test-PrinterPort .LINK https://github.com/pauby/oxygen/blob/master/docs/reset-printerdriver.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] [OutputType([boolean])] Param ( # Specifies the printer driver to reset. [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Name ) if (Test-PrinterDriver -Name $Name) { if (PSCmdlet.ShouldProcess($Name, 'Removing printer driver')) { Remove-PrinterDriver -Name $Name -ErrorAction SilentlyContinue } # check it's gone if (Test-PrinterDriver -Name $Name) { return $false } } # add the printer driver Add-PrinterDriver -Name $Name -ErrorAction SilentlyContinue # check it's been added if (Test-PrinterDriver -Name $Name) { return $true } else { return $false } } function Reset-PrinterPort { <# .SYNOPSIS Resets the printer port. .DESCRIPTION Resets the printer port configuration by removing then adding it with the new one. You do not need administrator privileges to use Reset-PrinterPort .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen https://www.github.com/pauby/oxygen History : v1.0 - 20/04/18 - Initial .INPUTS None .OUTPUTS [boolean] .EXAMPLE] Reset-PrinterPort -PortName "HPLJ" -PrinterHostAddress "192.168.10.100" Removes the printer port called HPLJ and adds it back again with the same name and IP host address of 192.168.10.100 .LINK Reset-Printer .LINK Reset-PrinterDriver .LINK Test-Printer .LINK Test-PrinterDriver .LINK Test-PrinterDriverStore .LINK Test-PrinterPort .LINK https://github.com/pauby/oxygen/blob/master/docs/reset-printerport.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] [OutputType([boolean])] Param ( # Specifies the Name of the port to be reset. You can get this name using Get-PrinterPort. [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$PortName, # Specifies the IP address of the printer port to be added. [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$PrinterHostAddress ) # check we have a port and remove it if (Test-PrinterPort -Name $PortName) { if (PSCmdlet.ShouldProcess($Name, 'Removing printer port')) { Remove-PrinterPort -Name $PortName -ErrorAction SilentlyContinue } # check the port is gone if (Test-PrinterPort -Name $PortName) { return $false } } # add the port and check it's now been added Add-PrinterPort -Name $PortName -PrinterHostAddress $PrinterHostAddress -ErrorAction SilentlyContinue if (Test-PrinterPort -Name $PortName) { $true } else { $false } } function Test-Printer { <# .SYNOPSIS Tests if the specified printer exists on the local computer. .DESCRIPTION Tests if the specified printer exists on the local computer. .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://www.github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial .INPUTS None .OUTPUTS [boolean] .EXAMPLE Test-Printer -Name "HP LaserJet 4" Tests if the printer named "HP LaserJet 4" exists on the local computer. .LINK Reset-Printer .LINK Reset-PrinterDriver .LINK Reset-PrinterPort .LINK Test-PrinterDriver .LINK Test-PrinterDriverStore .LINK Test-PrinterPort .LINK https://github.com/pauby/oxygen/blob/master/docs/test-printer.md #> [CmdletBinding()] [OutputType([boolean])] Param ( # Specified printer name to test. [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Name ) ([bool](Get-Printer | Where-Object { $_.Name -eq $Name } )) } function Test-PrinterDriver { <# .SYNOPSIS Tests if the printer driver is present on the system. .DESCRIPTION Tests if the printer driver is present on the system. .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://www.github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial .INPUTS None .OUTPUTS [boolean] .EXAMPLE Test-PrinterDriver "HP LaserJet 4" This would test if the printer driver 'HP LaserJet 4' was installed. .LINK Reset-Printer .LINK Reset-PrinterDriver .LINK Reset-PrinterPort .LINK Test-Printer .LINK Test-PrinterDriverStore .LINK Test-PrinterPort .LINK https://github.com/pauby/oxygen/blob/master/docs/test-printerdriver.md #> [CmdletBinding()] [OutputType([boolean])] Param ( # Printer driver name [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Name ) [bool](Get-PrinterDriver | Where-Object { $_.Name -eq $Name } ) } function Test-PrinterDriverStore { <# .SYNOPSIS Test if the specified printer driver exists in the printer driver store. .DESCRIPTION Test if the specified printer driver exists in the printer driver store. .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://www.github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial .INPUTS None .OUTPUTS [boolean] .EXAMPLE Test-PrinterDriverStore -Name "HP LaserJet PS" Tests if the printer driver named "HP LaserJet PS" exists in the printer driver store. .LINK Reset-Printer .LINK Reset-PrinterDriver .LINK Reset-PrinterPort .LINK Test-Printer .LINK Test-PrinterDriver .LINK Test-PrinterPort .LINK https://github.com/pauby/oxygen/blob/master/docs/test-printerdriverstore.md #> [CmdletBinding()] [OutputType([boolean])] Param ( # Specifies the name of the printer driver to test. [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Name ) # check if the driver is in the list already if (Test-PrinterDriver -Name $Name) { return $true } else { # try and install the driver - if it fails then the driver most likely does not exist in the store try { Add-PrinterDriver -Name $DriverName } catch { # if we get here then the driver will most likely not exist in the store so will need to be added return $false } # if we get here then the printer driver was added successfully - remove it (as we only wanted to test it) Remove-PrinterDriver -Name $DriverName return $true } } function Test-PrinterPort { <# .SYNOPSIS Tests if the specified printer port exists on the computer. .DESCRIPTION Tests if the specified printer port exists on the computer. .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://www.github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial .INPUTS None .OUTPUTS [boolean] .EXAMPLE Test-PrinterPort -PortName "TestPrinter" Tests whether the port named TestPrinter exisst on the computer. .LINK Reset-Printer .LINK Reset-PrinterDriver .LINK Reset-PrinterPort .LINK Test-Printer .LINK Test-PrinterDriver .LINK Test-PrinterDriverStore .LINK https://github.com/pauby/oxygen/blob/master/docs/test-printerport.md #> [CmdletBinding()] [OutputType([boolean])] Param ( # Specifies the name of the port to test. [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Name ) [bool](Get-PrinterPort | Where-Object { $_.Name -eq $Name } ) } function Import-Registry { <# .SYNOPSIS This is just a wrapper around 'regedit /s' .DESCRIPTION This is just a wrapper around 'regedit /s' .INPUTS None .OUTPUTS None .EXAMPLE Import-Registry -Path 'mychanges.reg' Will import the file 'mychanges.reg' into the registry. .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : 1.0 - 20/04/18 - Initial release .LINK https://github.com/pauby/oxygen/blob/master/docs/import-registry.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] Param ( [Parameter(Mandatory, Position = 0)] [ValidateScript({ Test-Path $_ })] [string]$Path ) if ($PSCmdlet.ShouldProcess($Path, 'Import file to the registry')) { regedit /s $Path } } function Add-Acl { <# .SYNOPSIS Set an ace on an object. .DESCRIPTION Set an ace, created using New-Acl, on an object. .INPUTS None .OUTPUTS System.Security.AccessControl.FileSecurity .EXAMPLE Add-Acl -Path 'C:\Windows\Notepad.exe' -AceObject $aceObj Adds the access control entry object, $aceObj created using New-Acl, to 'C:\Windows\Notepad.exe' .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : v1.0 - 22/04/18 - Initial Code was created using https://technet.microsoft.com/en-us/library/ff730951.aspx as a basis. .LINK New-AclObject .LINK Set-Owner .LINK https://github.com/pauby/oxygen/blob/master/docs/add-acl.md #> [CmdletBinding()] Param ( # Path to the object to set the acl on. [Parameter(Mandatory = $true)] [string]$Path, # Ace / Acl to set. Create this using New-Acl. [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [Alias('Acl', 'AclObject')] [System.Security.AccessControl.FileSystemAccessRule]$AceObject ) Write-Verbose "Retrieving existing ACL from $Path" $objACL = Get-ACL -Path $Path $objACL.AddAccessRule($AceObject) Write-Verbose "Setting ACL on $Path" Set-ACL -Path $Path -AclObject $objACL } function New-AclObject { <# .SYNOPSIS Creates a new ACL object. .DESCRIPTION Creates a new ACL object for use with module -Acl* functions. .INPUTS None .OUTPUTS System.Security.Principal.NTAccount .EXAMPLE New-AclObject -SamAccountName 'testuser' -Permission 'Modify' Creates an ACL object to Allow Modify permissions without inheritance or propogation for the samAccountName 'testuser' .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial Code was created using https://technet.microsoft.com/en-us/library/ff730951.aspx as a basis. .LINK Add-Acl .LINK Set-Owner .LINK https://github.com/pauby/oxygen/blob/master/docs/new-aclobject.md #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'No state is being changed')] Param ( # samAccountName to create the object for [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [Alias('Sam', 'Username')] [string]$SamAccountName, # Permissions / rights to be applied (see https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.filesystemrights(v=vs.110).aspx for information) [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [Alias('AccessRight')] [System.Security.AccessControl.FileSystemRights]$Permission, # Allow or deny the access rule (see https://msdn.microsoft.com/en-us/library/w4ds5h86(v=vs.110).aspx for information). # Default is 'Allow' [ValidateNotNullOrEmpty()] [System.Security.AccessControl.AccessControlType]$AccessControl = 'Allow', # Inheritance rules to be applied (see https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.inheritanceflags(v=vs.110).aspx for information). # Default is 'None' [ValidateNotNullOrEmpty()] [Alias('InheritanceFlag')] [System.Security.AccessControl.InheritanceFlags]$Inheritance = 'None', # Propogation method for the rules (see https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.propagationflags(v=vs.110).aspx for information). # Default is 'None' [ValidateNotNullOrEmpty()] [Alias('PropogationFlag')] [System.Security.AccessControl.PropagationFlags]$Propagation = 'None' ) [OutputType([System.Security.AccessControl.FileSystemAccessRule])] $objUser = New-Object System.Security.Principal.NTAccount($Username) New-Object System.Security.AccessControl.FileSystemAccessRule($objUser, $Permission, $Inheritance, $Propagation, $AccessControl) } # < PS 5 compatibility Add-Type -TypeDefinition @" public enum ComplexityOptions { Upper, Lower, Number, Symbol } "@ function New-ComplexPassword { <# .SYNOPSIS Creates a complex password. .DESCRIPTION Creates a complex password using one or more of upper case, lower case, numbers and symbols. .INPUTS None .OUTPUTS [string] .EXAMPLE New-ComplexPassword Create a password with a length of 12 and using upper, lower, numbers and symbols. .EXAMPLE New-ComplexPassword -Length 25 -Complexity Upper, Lower Create a password with a length of 25 characters and using upper and lower case characters. .EXAMPLE New-ComplexPassword -Exclude @('0') -Complexity Upper, Lower, Number Create a password with a length of 12, using upper, lower and numbers but excluding '0' (zero) .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial .LINK https://github.com/pauby/oxygen/blob/master/docs/new-complexpassword.md #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'No state is being changed')] [CmdletBinding()] [OutputType([string])] Param ( # Length of the password to generate. By default this is 12. [ValidateRange(1, 999)] [Int] $Length = 12, # Characters to not include in the password. For example you may to # choose to exclude '0' (zero) as it is visually close to 'O' (capital # oh) [Char[]] $Exclude, # Create the password using these options. Valid values are Upper, Lower, Number and Symbol. [ComplexityOptions[]] $Complexity = @( [ComplexityOptions]::Upper, [ComplexityOptions]::Lower, [ComplexityOptions]::Number, [ComplexityOptions]::Symbol ) ) #! keep the Complexity default values all on one line or an error is generated when creating the external help file # initialise the pool of characters to create password from $pool = '' switch ($Complexity) { 'Upper' { # uppercase chars 'A' to 'Z' Write-Verbose "Using upper case characters A-Z" $pool += (65..90 | ForEach-Object { [char]$_ }) -join '' continue } 'Lower' { # lowercase chars 'a' to 'z' Write-Verbose "Using lower case characters a-z" $pool += (97..122 | ForEach-Object { [char]$_ }) -join '' continue } 'Number' { # integers 0 to 9 Write-Verbose "Using numbers 0-9" $pool += (0..9 | ForEach-Object { $_ }) -join '' continue } 'Symbol' { Write-Verbose "Using symbols" $pool += '!"#$%&''()*+,-./:;<=>?@[\]^_`{|}~' } } # end Switch # initialize the password $pwd = '' while ($pwd.Length -lt $Length) { # randomly generate the index of which pool character to use $index = Get-Random -Maximum $pool.Length # check that the character chosen is not on the exclude list if ($Exclude -cnotcontains $pool[$index]) { $pwd += $pool[$index] } else { Write-Verbose "Skipped $($pool[$index])" } } $pwd } function Set-AclOwner { <# .SYNOPSIS Set the owner of an object. .DESCRIPTION Sets the owner of an object. This is related to the 'Acl' group of cmdlets, hence the name. .INPUTS None .OUTPUTS System.Security.AccessControl.FileSecurity .EXAMPLE Set-AclOwner -Path c:\myfile.txt -SamAccountName 'chewie' Will set the account (group or user) 'chewie' to be the owner of 'c:\myfile.txt' .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial .LINK Add-Acl .LINK New-AclObject .LINK https://github.com/pauby/oxygen/blob/master/docs/set-aclowner.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] Param ( # Path to set the owner of. [Parameter(Mandatory, HelpMessage = 'Path to set owner of.')] [ValidateScript( { Test-Path $_ })] [string]$Path, # The samAccountName to set as the object owner. [Parameter(Mandatory, HelpMessage = 'The samAccountName to set as the object owner.')] [Alias('Sam', 'Username')] [string]$SamAccountName ) Write-Verbose "Retrieving existing ACL from '$Path'" $acl = Get-ACL -Path $Path $account = New-Object System.Security.Principal.NTAccount($SamAccountName) Write-Verbose "Setting ACL owner to '$SamAccountName'" if ($PSCmdlet.ShouldProcess($Path, "Setting object owner to '$SamAccountName'")) { $acl.SetOwner($account) Write-Verbose "Setting ACL on '$Path'" Set-Acl -Path $Path -AclObject $acl } } function Set-UAC { <# .SYNOPSIS Enables or disables UAC. .DESCRIPTION Enables or disables UAC by change the EnableLUA key in the registry at HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System. .EXAMPLE Set-UAC -Enable Enables UAC on the local computer. .EXAMPLE Set-UAC -Disable Disables UAC on the local computer. .INPUTS None .OUTPUTS [PSCustomObject] .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : 1.0 - 21/04/18 - Initial release .LINK https://github.com/pauby/oxygen/blob/master/docs/set-uac.md #> [OutputType([PSCustomObject])] [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] Param( [Parameter(ParameterSetName = 'Enable')] [switch] $Enable, [Parameter(ParameterSetName = 'Disable')] [switch] $Disable ) if ($Enable) { Write-Verbose "Enabling UAC." $action = 'Disabling' $state = 1 } else { Write-Verbose "Disabling UAC." $action = 'Enabling' $state = 0 } if ($PSCmdlet.ShouldProcess('UAC', $action)) { New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System" ` -Name 'EnableLUA' -Value $state -PropertyType 'DWord' -Force } } function Add-WindowsDriverPackage { <# .SYNOPSIS Adds a Windows driver to the driver store. .DESCRIPTION This function is a wrapper for the pnputil.exe program. It adds a Windows driver to the driver store by passing the .inf file. $_ Using the -Install switch will also install install the driver package(s) too. The functions' return value is dependent on the errorlevel from pnputil.exe. If the errorlevel is 0 then this indicates successfully and true is returned, otherwise false is returned. .INPUTS None .OUTPUTS [boolean] .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial .EXAMPLE Add-WindowsDriverPackage -Path c:\drivers\usbcam.inf Adds c:\drivers\usbcam.inf driver package to the driver store. .EXAMPLE Add-WindowsDriverPackage -Path c:\drivers\*.inf -Install Adds and installs all *.inf driver packages from c:\drivers .LINK https://github.com/pauby/oxygen/blob/master/docs/add-windowsdriverpackage.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] [OutputType([boolean])] Param ( # Path to the .inf file of the drive rpackage. Note that this can use wildcards. # So you can you c:\drivers\*.inf. # The path will be checked and exception thrown if it does not exist. [Parameter(Mandatory, Position = 0)] [ValidateScript( { Test-Path $_ } )] [string]$Path, # Will install the driver package(s). [switch]$Install ) if ($Install.IsPresent) { Write-Verbose "Installing driver package '$Path' to the store." $cmd = "pnputil.exe -i -a $Path" $msg = 'Installing driver package and adding it to the store' } else { Write-Verbose "Adding driver package $Path to the store." $cmd = "pnputil.exe -a $Path" $msg = 'Adding driver package to the store' } if ($PSCmdlet.ShouldProcess($Path, $msg)) { $cmd | Out-Null } if ($LastExitCode -ne 0) { Write-Verbose "Driver package $Path failed to be added / installed." $false } else { Write-Verbose "Driver package $Path was added / installed" } $true } function Disable-WindowsPageFile { <# .SYNOPSIS Disables the Windows pagefile. .DESCRIPTION Disables the Windows pagefile on the local computer. .EXAMPLE Disable-WindowsPageFile Disables the Windows page file on the local computer. .INPUTS None .OUTPUTS [boolean] .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : 1.0 - 20/04/18 - Initial release .LINK Enable-PageFile .LINK Remove-PageFile .LINK https://github.com/pauby/oxygen/blob/master/docs/disable-windowspagefile.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] [OutputType([boolean])] Param( # Force disabling the pagefile regardless of it's current state. [switch] $Force ) $cs = Get-CimInstance -ClassName Win32_ComputerSystem if ($Force.IsPresent -or $cs.AutomaticManagedPagefile) { if ($PSCmdlet.ShouldProcess('Windows PageFile', 'Disabling')) { try { $cs.AutomaticManagedPagefile = $false $PutOptions = New-Object System.Management.PutOptions $PutOptions.Type = 2 $cs.PsBase.Put() return $true } catch { return $false } } } $false } function Enable-WindowsPageFile { <# .SYNOPSIS Enables the Windows pagefile. .DESCRIPTION Enables the Windows pagefile on the local computer. .EXAMPLE Enable-WindowsPageFile Enables the Windows page file on the local computer. .INPUTS None .OUTPUTS [boolean] .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : 1.0 - 20/04/18 - Initial release .LINK Disable-PageFile .LINK Remove-PageFile .LINK https://github.com/pauby/oxygen/blob/master/docs/enable-windowspagefile.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] [OutputType([boolean])] Param ( # Force enbling the pagefile regardless of it's current state. [switch] $Force ) $cs = Get-CimInstance -ClassName Win32_ComputerSystem if ($Force.IsPresent -or !$cs.AutomaticManagedPagefile) { if ($PSCmdlet.ShouldProcess('Windows PageFile', 'Enabling')) { try { $cs.AutomaticManagedPagefile = $true $PutOptions = New-Object System.Management.PutOptions $PutOptions.Type = 2 $cs.PsBase.Put() return $true } catch { return $false } } } $false } function Get-OS { <# .SYNOPSIS Gets details of the operating system. .DESCRIPTION Gets details of the operating system. This function is a nice wrapper around the Get-CimInstance Win32_OperatingSystem call. It does create a hashtable with already determined information for the platform and type. The format of the data returned is: Name Value ---- ----- version 10.0.16299 name Microsoft Windows 10 Pro architecture 64-bit type Windows platform Workstation buildnumber 16299 * The 'platform' field can be 'Workstation', 'Domain Controller' or 'Server'. * The 'type' field will be 'Windows' or 'Unknown'. .EXAMPLE Get-OS Returns information about the operating system. .INPUTS None .OUTPUTS [hashtable] .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : 1.0 - 20/04/18 - Initial release .LINK Test-IsNonInteractiveShell .LINK https://github.com/pauby/oxygen/blob/master/docs/get-os.md #> [CmdletBinding()] [OutputType([hashtable])] Param ( # Get operating system information of this computer. Defaults to local # computer. [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)] [string]$ComputerName = '.' ) Begin {} Process { try { $osData = Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $ComputerName } catch { throw $_ } @{ name = $osData.Caption architecture = $osData.OSArchitecture platform = switch ($osData.ProductType) { 1 { 'Workstation' } 2 { 'Domain Controller' } 3 { 'Server' } } type = switch ($osData.OSType) { 18 { 'Windows'; break } default { 'Unknown' } } version = $osData.Version buildnumber = $osData.BuildNumber } } End {} } function Get-WindowsSpecialFolderPath { <# .SYNOPSIS Gets the path of a Windows special folder. .DESCRIPTION Gets the path of a Windows special folder such as Network Shortcuts, Desktop, etc. This is a wrapper around [Environment]::GetFolderPath() .INPUTS None .OUTPUTS [string] .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial .EXAMPLE Get-WindowsSpecialFolderPath -Name "NetworkShortcuts" Gets the network shortcuts folder path. .LINK https://github.com/pauby/oxygen/blob/master/docs/get-windowsspecialfolderpath.md #> [CmdletBinding()] [OutputType([string])] Param ( # The name of the special folder. This name must match one from the list # at https://msdn.microsoft.com/en-us/library/system.environment.specialfolder.aspx [Parameter(Mandatory)] [ValidateScript( { $_ -in [Environment+SpecialFolder]::GetNames([Environment+SpecialFolder]) } )] [string]$Name ) [Environment]::GetFolderPath($Name) } function Remove-WindowsPageFile { <# .SYNOPSIS Removes the Windows PageFile. .DESCRIPTION Removes the Windows PageFile. .EXAMPLE Remove-PageFile Removes the Windows Pagefile on the current computer. .INPUTS None .OUTPUTS [boolean] .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : 1.0 - 20/04/18 - Initial release .LINK Disable-PageFile .LINK Enable-PageFile .LINK https://github.com/pauby/oxygen/blob/master/docs/remove-windowspagefile.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] [OutputType([boolean])] Param () $pg = Get-CimInstance -ClassName Win32_PageFileUsage if ($pg) { if ($PSCmdlet.ShouldProcess('Windows Pagefile', 'Removing')) { try { Remove-Item $pg.Name -Force -ErrorAction Stop return $true } catch { return $false } } } $false } function Set-WindowsRegion { <# .SYNOPSIS Sets the Regional Settings for Windows. .DESCRIPTION Sets the Regional Settings for Windows like you would do by going to Control Panel -> Regional Settings This function is basically a wrapper around rundll32.exe. .INPUTS None .OUTPUTS None .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial .EXAMPLE Set-Region -Path c:\temp\region-uk.xml Sets the regional settings to that contained in c:\temp\region-uk.xml .LINK https://github.com/pauby/oxygen/blob/master/docs/set-windowsregion.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] Param ( # Path to the regional settings XML file. [Parameter(Mandatory, Position = 0)] [ValidateScript( { Test-Path $_ } )] [string]$Path ) if ($PSCmdlet.ShouldProcess('Regional Settings', "Applying the settings in '$Path'")) { $cmd = "intl.cpl,,/f:$Path" rundll32.exe shell32,Control_RunDLL "$cmd" } } function Test-IsInteractiveShell { <# .SYNOPSIS Tests if the current shell is noninteractive. .DESCRIPTION First, we check `[Environment]::UserInteractive` to determine if the shell is running interactively. An example of not running interactively would be if the shell is running as a service. If we are running interactively, we check the Command Line Arguments to see if the `-NonInteractive` switch was used or an abbreviation of the switch. .INPUTS None .OUTPUTS [boolean] .NOTES Author : Vertigion (https://github.com/Vertigion/Test-IsNonInteractiveShell) Project : Oxygen (https://github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial .LINK Get-OS .LINK https://github.com/pauby/oxygen/blob/master/docs/test-isinteractiveshell.md #> [CmdletBinding()] [OutputType([boolean])] Param() ([Environment]::UserInteractive -and (-not ([Environment]::GetCommandLineArgs() | Where-Object { $_ -like '-NonI*' }))) } # Taken from https://social.technet.microsoft.com/Forums/scriptcenter/en-US/fd34260e-ee4c-47c5-8c69-872a5239745f/add-a-network-location-via-script?forum=ITCG function Set-NetworkShortcut { <# .SYNOPSIS Creates or replaces a network shortcut. .DESCRIPTION Creates or replaces a network shortcut. .EXAMPLE Set-NetworkShortcut -Name 'MyShare' -DestinationUri '\\myserver\share' Creates a network shortcut called 'MyShare' pointing to '\\myserver\share'. .EXAMPLE Set-NetworkShortcut -Name 'MyShare' -DestinationUri '\\myserver\share' -Icon 304 Creates a network shortcut called 'MyShare' pointing to '\\myserver\share' with icon number 304. .INPUTS None .OUTPUTS [PSObject] .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : 1.0 - 20/04/18 - Initial release .LINK Set-Shortcut .LINK https://github.com/pauby/oxygen/blob/master/docs/set-networkshortcut.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] Param ( # Display name of the short to be created. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [string] $Name, # The destination URI for the shortcut. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [string] $DestinationUri, # Username to set the shortcut for. [ValidateNotNullOrEmpty()] [ValidateScript( { Test-Path (Join-Path -Path (Split-Path -Path $env:PUBLIC -Parent) -ChildPath $_) })] [string] $Username = $env:USERNAME, # Number of the icon to use. By default this is 275. # Find more icons http://help4windows.com/windows_7_shell32_dll.shtml [ValidateNotNullOrEmpty()] [ValidateRange(0, 305)] [int32] $Icon = 275, [switch] $Force ) $shortcutPath = Join-Path -Path (Split-Path -Path $env:PUBLIC -Parent) -ChildPath "$Username\appdata\Roaming\Microsoft\Windows\Network Shortcuts" # check if the .lnk file exists for the shortcut $shortcutFullPath = Join-Path -Path $shortcutPath -ChildPath $Name if ($Force.IsPresent -and (Test-Path -Path $shortcutFullPath)) { if ($PSCmdlet.ShouldProcess($shortcutFullPath, 'Removing network shortcut')) { Write-Verbose "Deleting network shortcut '$shortcutFullPath' as '-Force' parameter provided." Remove-Item -Path $shortcutFullPath -Force } } # create the folder Write-Verbose "Creating the shortcut folder '$shortcutFullPath'." New-Item -Name $Name -Path $shortcutFullPath -Type Directory | Out-Null # Create the ini file $iniPath = Join-Path -Path $shortcutFullPath -ChildPath 'Desktop.ini' Write-Verbose "Creating the INI file '$iniPath'." @" [.ShellClassInfo] CLSID2={0AFACED1-E828-11D1-9187-B532F1E9575D} Flags=2 ConfirmFileOp=1 "@ | Out-File -FilePath $iniPath # Create the shortcut file $lnkPath = Join-Path -Path $shortcutFullPath -ChildPath 'target.lnk' Write-Verbose "Creating shortcut .lnk '$lnkPath'." $shortcut = (New-Object -ComObject WScript.Shell).Createshortcut($lnkPath) $shortcut.TargetPath = $DestinationUri $shortcut.IconLocation = "%SystemRoot%\system32\SHELL32.DLL, $Icon" $shortcut.Description = $DestinationUri $shortcut.WorkingDirectory = $DestinationUri $shortcut.Save() Set-ItemProperty (Join-Path -Path $shortcutFullPath -ChildPath 'Desktop.ini') ` -Name Attributes -Value ([IO.FileAttributes]::System -bxor [IO.FileAttributes]::Hidden) Set-ItemProperty $shortcutFullPath -Name Attributes -Value ([IO.FileAttributes]::ReadOnly) } function Set-Shortcut { <# .SYNOPSIS Sets a Windows shortcut. .DESCRIPTION Sets a Windows shortcut. Do not sue this to create a network shortcut as it will not give you the results you need. Use Set-NetworkShoertcut instead. .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://www.github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial .INPUTS None .OUTPUTS [boolean] .EXAMPLE Set-Shortcut -Path 'c:\user\joe\desktop\notepad.lnk' -Target 'c:\windows\system32\notepad.exe' Creates a shortcut to c:\windows\system32\notepad.exe on the desktop of the user 'joe'. .LINK Set-NetworkShortcut .LINK https://github.com/pauby/oxygen/blob/master/docs/set-shortcut.md #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] [OutputType([boolean])] Param ( # Path to the shortcut file. Should end with '.lnk'. The parent path of this must exist. # For example, if the path is c:\windows\system32\notepad.exe then c:\windows\system32 must exist. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateScript( { Test-Path -Path (Split-Path -Path $_ -Parent) } )] [string] $Path, # The destination of the shortcut. This could be an application or a URL. [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [string] $DestinationUri, # Remove the destination shortcut if it exists [switch] $Force ) # delete the shortcut if it already exists if ($Force.IsPresent -and (Test-Path -Path $Path)) { if ($PSCmdlet.ShouldProcess($Path, 'Removing shortcut')) { Write-Verbose "Deleting shortcut '$Path' as '-Force' parameter provided." Remove-Item -Path $Path -Force } } # Create the shortcut $WScriptShell = New-Object -ComObject WScript.Shell $Shortcut = $WScriptShell.CreateShortcut($Path) $Shortcut.TargetPath = $DestinationUri try { $Shortcut.Save() } catch { $false } $true } function Test-IsAccountEmptyPassword { <# .SYNOPSIS Checks if an account password is empty. .DESCRIPTION Tests whether an account password is empty / blank. .EXAMPLE Test-EmptyPassword -SamAccountName 'Administrator' Tests if the 'Administrator' account on the local computer has an empty / blank password. .EXAMPLE Test-EmptyPassword -SamAccountName 'Administrator' -ComputerName 'server01' Tests if the 'Administrator' account on'server01' has an empty / blank password. .INPUTS None .OUTPUTS [boolean] .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : 1.0 - 20/04/18 - Initial release .LINK Test-IsAdmin .LINK https://github.com/pauby/oxygen/blob/master/docs/test-isaccountemptypassword.md #> [CmdletBinding()] [OutputType([boolean])] Param ( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [Alias('Username')] [string] $SamAccountName, [ValidateNotNullOrEmpty()] [string] $ComputerName = '.' ) $user = [ADSI]("WinNT://$Computername/$SamAccountName, user") try { $user.invoke("ChangePassword", "", "DummyPassword") } catch { return $false } $user.invoke("ChangePassword", "DummyPassword", "") $true } function Test-IsAdmin { <# .SYNOPSIS Test for elevated privileges. .DESCRIPTION Test if the current session has elevated privileges. Returns true if the current session has elevated privileges and false otherwise. .INPUTS None .OUTPUTS [boolean] .EXAMPLE Test-IsAdmin Tests to see if the current session has elevated privileges. .NOTES Author : Andy Arismendi (http://stackoverflow.com/users/251123/andy-arismendi) Project : Oxygen (https://github.com/pauby/oxygen) History : v1.0 - 20/04/18 - Initial Also see http://stackoverflow.com/questions/9999963/powershell-test-admin-rights-within-powershell-script .LINK Test-IsInteractiveUser .LINK https://github.com/pauby/oxygen/blob/master/docs/test-isadmin.md #> [CmdletBinding()] [OutputType([boolean])] Param () $identity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object Security.Principal.WindowsPrincipal -ArgumentList $identity $principal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator) } function Test-IsInteractiveUser { <# .SYNOPSIS Tests if the current user is interactive. .DESCRIPTION Tests if the current user is interactive. .EXAMPLE Test-IsInteractiveUser Return $true if the current user is interactive, $false otherwise. .INPUTS None .OUTPUTS [boolean] .NOTES Author : Paul Broadwith (https://github.com/pauby) Project : Oxygen (https://github.com/pauby/oxygen) History : 1.0 - 21/04/18 - Initial release .LINK Test-IsAdmin .LINK https://github.com/pauby/oxygen/blob/master/docs/test-isinteractiveuser.md #> [CmdletBinding()] [OutputType([boolean])] Param() [Environment]::UserInteractive } |