where can i find the Get-WmiObject file location in powershell? - windows

I would like to change some code in the Get-wmiObject file itself to do some functionality for me and replace some others. most important thing is to change some command output for some reason. how can i do that or is it possible ?

As Santiago pointed out, proxy functions would be the right choice for modifying native code behaviour.
Step 1: Generate the proxy function
You can do this by:
$Command = Get-Command -Name Get-WmiObject
$ProxyFunction = [System.Management.Automation.ProxyCommand]::Create($Command)
$ProxyFunction | Out-File 'C:\temp\Proxy.ps1' -Force
The above will generate parameters for the Get-WmiObject plus the "calling mechanism" for the Get-WmiObject command, in C:\temp\Proxy.ps1
Step 2: Write your code
You can now write wrapper code. In the below example, I wrote some code to display PowerShell version (in the verbose stream) along with the original output.
Original working:
> Get-WmiObject win32_operatingsystem
SystemDirectory : C:\Windows\system32
Organization :
BuildNumber : 1234
RegisteredUser : 1234
SerialNumber : 1234
Version : 1.2.3.4
Proxy function working:
> Get-WmiObject win32_operatingsystem
SystemDirectory : C:\Windows\system32
Organization :
BuildNumber : 1234
RegisteredUser : 1234
SerialNumber : 1234
Version : 1.2.3.4
VERBOSE: PowerShell version is: 5.1.19041.1682
Full code can be found below. Keep in mind, most of the code was generated from step 1. I just added the output from step 1, plus my custom code into a function with the same name as the original function we're proxying.
If you want this function to be available as soon as you open a new PowerShell window, put it in your $PROFILE.
function Get-WmiObject
{
[CmdletBinding(DefaultParameterSetName='query', HelpUri='https://go.microsoft.com/fwlink/?LinkID=113337', RemotingCapability='OwnedByCommand')]
param(
[Parameter(ParameterSetName='query', Mandatory=$true, Position=0)]
[Parameter(ParameterSetName='list', Position=1)]
[Alias('ClassName')]
[string]
${Class},
[Parameter(ParameterSetName='list')]
[switch]
${Recurse},
[Parameter(ParameterSetName='query', Position=1)]
[string[]]
${Property},
[Parameter(ParameterSetName='query')]
[string]
${Filter},
[switch]
${Amended},
[Parameter(ParameterSetName='query')]
[Parameter(ParameterSetName='WQLQuery')]
[switch]
${DirectRead},
[Parameter(ParameterSetName='list')]
[switch]
${List},
[Parameter(ParameterSetName='WQLQuery', Mandatory=$true)]
[string]
${Query},
[switch]
${AsJob},
[Parameter(ParameterSetName='class')]
[Parameter(ParameterSetName='path')]
[Parameter(ParameterSetName='WQLQuery')]
[Parameter(ParameterSetName='query')]
[Parameter(ParameterSetName='list')]
[System.Management.ImpersonationLevel]
${Impersonation},
[Parameter(ParameterSetName='path')]
[Parameter(ParameterSetName='class')]
[Parameter(ParameterSetName='WQLQuery')]
[Parameter(ParameterSetName='query')]
[Parameter(ParameterSetName='list')]
[System.Management.AuthenticationLevel]
${Authentication},
[Parameter(ParameterSetName='path')]
[Parameter(ParameterSetName='class')]
[Parameter(ParameterSetName='WQLQuery')]
[Parameter(ParameterSetName='query')]
[Parameter(ParameterSetName='list')]
[string]
${Locale},
[Parameter(ParameterSetName='WQLQuery')]
[Parameter(ParameterSetName='class')]
[Parameter(ParameterSetName='path')]
[Parameter(ParameterSetName='query')]
[Parameter(ParameterSetName='list')]
[switch]
${EnableAllPrivileges},
[Parameter(ParameterSetName='query')]
[Parameter(ParameterSetName='class')]
[Parameter(ParameterSetName='WQLQuery')]
[Parameter(ParameterSetName='path')]
[Parameter(ParameterSetName='list')]
[string]
${Authority},
[Parameter(ParameterSetName='path')]
[Parameter(ParameterSetName='class')]
[Parameter(ParameterSetName='WQLQuery')]
[Parameter(ParameterSetName='query')]
[Parameter(ParameterSetName='list')]
[pscredential]
[System.Management.Automation.CredentialAttribute()]
${Credential},
[int]
${ThrottleLimit},
[Parameter(ParameterSetName='WQLQuery')]
[Parameter(ParameterSetName='class')]
[Parameter(ParameterSetName='path')]
[Parameter(ParameterSetName='query')]
[Parameter(ParameterSetName='list')]
[Alias('Cn')]
[ValidateNotNullOrEmpty()]
[string[]]
${ComputerName},
[Parameter(ParameterSetName='class')]
[Parameter(ParameterSetName='WQLQuery')]
[Parameter(ParameterSetName='query')]
[Parameter(ParameterSetName='list')]
[Parameter(ParameterSetName='path')]
[Alias('NS')]
[string]
${Namespace})
begin
{
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
{
$PSBoundParameters['OutBuffer'] = 1
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Get-WmiObject', [System.Management.Automation.CommandTypes]::Cmdlet)
$scriptCmd = {& $wrappedCmd #PSBoundParameters }
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
} catch {
throw
}
}
process
{
if ($Class -eq 'win32_operatingsystem')
{
Write-Verbose -Message "PowerShell version is: $($PSVersionTable.PSVersion)" -Verbose
}
try {
$steppablePipeline.Process($_)
} catch {
throw
}
}
end
{
try {
$steppablePipeline.End()
} catch {
throw
}
}
<#
.ForwardHelpTargetName Microsoft.PowerShell.Management\Get-WmiObject
.ForwardHelpCategory Cmdlet
#>
}

Related

How to Change the My Computer Desktop Icon Using Powershell?

I am trying to learn a little bit of Shell-Scripting, as Test-Automation seems to get trendier these days.
My grasp of Powershell is quite generic. My current goal is to change the My Computer desktop icon.
There are some things of the Microsoft Windows 10 operating system that I have not touched yet using Powershell. I hope that maybe some more prolific writers than myself are able to give me a hand in reaching this goal.
I have just tested two snippets that have surprisingly run successfully on their first attempts.
The first one may be called as Create_Shortcut.PS1 and creates a desktop icon for the command-line preprocessing system where batch files may be run.
# Creates the command-line desktop icon.
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
$TargetFile = "C:\Windows\System32\Cmd.Exe"
$ShortcutFile = "\\ISXPFV01.hd00.example.com\us_qv2_dem_user_data_pool_nra$\EE65037.HD00\Desktop\Command-Line.Lnk"
$WScriptShell = New-Object -COMObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($ShortcutFile)
$Shortcut.TargetPath = $TargetFile
$Shortcut.Save()
The second one might be called as Rename_My_Computer.PS1 and it renames the My Computer desktop icon.
# Changes the My Computer desktop icon name from "This PC" to "VSDC0365".
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
$My_Computer = 17
$Shell = New-Object -COMObject Shell.Application
$NSComputer = $Shell.Namespace($My_Computer)
$NSComputer.Self.Name = $Env:COMPUTERNAME
What I am interested in could prove to be extremely simple to someone who is more experienced in Powershell than myself. I need to change the My Computer desktop icon by specifying its path.
As I have not reached yet this goal, any kind of help on this subject is highly appreciated.
Thanks for reading.
UPDATE after #Theo's great comment:
A new surprisingly working snippet, that manages to produce the My Computer desktop icon:
# HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel\
# {20D04FE0-3AEA-1069-A2D8-08002B30309D}
# 0 = show
# 1 = hide
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
$Path = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel"
$Name = "{20D04FE0-3AEA-1069-A2D8-08002B30309D}"
$Exist = "Get-ItemProperty -Path $Path -Name $Name"
if ($Exist)
{
Set-ItemProperty -Path $Path -Name $Name -Value 0
}
Else
{
New-ItemProperty -Path $Path -Name $Name -Value 0
}
Now, all that I have to do is to somehow programatically press F5 in order to refresh the Desktop View, after somehow setting the settings that he has mentioned in his comment.
Another UPDATE related to the refresh:
Another surprisingly working snippet, that refreshes the Desktop View:
# Refresh Desktop Ability
$Definition = #'
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
public static void Refresh() {
SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
}
'#
Add-Type -MemberDefinition $Definition -Namespace WinAPI -Name Explorer
# Refresh desktop icons
[WinAPI.Explorer]::Refresh()
Now everything that is still left is to change the My Computer desktop icon somehow before the refresh.
UPDATE related to Taking the Ownership of that Registry Key:
Tricky stuff. I had no idea that it can get so complicated.
Currently, it fails with error messages starting with the following one:
PS Y:\> Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.PS1
True
Exception calling "OpenSubKey" with "3" argument(s): "Requested registry access is not allowed."
At Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.PS1:139 char:1
+ $RegKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey( ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SecurityException
This is the content of the Change_Registry_Key.PS1 file:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Function Enable-Privilege {
Param(
## The privilege to adjust.
[ValidateSet(
"SeAssignPrimaryTokenPrivilege"
, "SeAuditPrivilege"
, "SeBackupPrivilege"
, "SeChangeNotifyPrivilege"
, "SeCreateGlobalPrivilege"
, "SeCreatePagefilePrivilege"
, "SeCreatePermanentPrivilege"
, "SeCreateSymbolicLinkPrivilege"
, "SeCreateTokenPrivilege"
, "SeDebugPrivilege"
, "SeEnableDelegationPrivilege"
, "SeImpersonatePrivilege"
, "SeIncreaseBasePriorityPrivilege"
, "SeIncreaseQuotaPrivilege"
, "SeIncreaseWorkingSetPrivilege"
, "SeLoadDriverPrivilege"
, "SeLockMemoryPrivilege"
, "SeMachineAccountPrivilege"
, "SeManageVolumePrivilege"
, "SeProfileSingleProcessPrivilege"
, "SeRelabelPrivilege"
, "SeRemoteShutdownPrivilege"
, "SeRestorePrivilege"
, "SeSecurityPrivilege"
, "SeShutdownPrivilege"
, "SeSyncAgentPrivilege"
, "SeSystemEnvironmentPrivilege"
, "SeSystemProfilePrivilege"
, "SeSystemtimePrivilege"
, "SeTakeOwnershipPrivilege"
, "SeTcbPrivilege"
, "SeTimeZonePrivilege"
, "SeTrustedCredManAccessPrivilege"
, "SeUndockPrivilege"
, "SeUnsolicitedInputPrivilege")]
$Privilege
## The process on which to adjust the privilege. Defaults to the current process.
, $ProcessId = $Pid
## Switch to disable the privilege, rather than enable it.
, [Switch] $Disable
)
$Definition = #'
using System;
using System.Runtime.InteropServices;
public class AdjPriv
{
[DllImport( "advapi32.dll"
, ExactSpelling = true
, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges( IntPtr htok
, bool disall
, ref TokPriv1Luid newst
, int len
, IntPtr prev
, IntPtr relen);
[DllImport( "advapi32.dll"
, ExactSpelling = true
, SetLastError = true)]
internal static extern bool OpenProcessToken( IntPtr h
, int acc
, ref IntPtr phtok);
[DllImport( "advapi32.dll"
, SetLastError = true)]
internal static extern bool LookupPrivilegeValue( string host
, string name
, ref long pluid);
[StructLayout( LayoutKind.Sequential
, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool EnablePrivilege( long processHandle
, string privilege
, bool disable)
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = new IntPtr(processHandle);
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken( hproc
, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
, ref htok);
tp.Count = 1;
tp.Luid = 0;
if(disable)
{
tp.Attr = SE_PRIVILEGE_DISABLED;
}
else
{
tp.Attr = SE_PRIVILEGE_ENABLED;
}
retVal = LookupPrivilegeValue( null
, privilege
, ref tp.Luid);
retVal = AdjustTokenPrivileges( htok
, false
, ref tp
, 0
, IntPtr.Zero
, IntPtr.Zero);
return retVal;
}
}
'#
$ProcessHandle = (Get-Process -Id $ProcessId).Handle
$Type = Add-Type $Definition -PassThru
$Type[0]::EnablePrivilege($processHandle, $Privilege, $Disable)
}
Enable-Privilege SeTakeOwnershipPrivilege
# Change Owner to the local Administrators group.
$RegKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey( `
"CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}" `
, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree `
, [System.Security.AccessControl.RegistryRights]::TakeOwnership)
$RegACL = $RegKey.GetAccessControl()
$RegACL.SetOwner([System.Security.Principal.NTAccount]"Administrators")
$RegKey.SetAccessControl($RegACL)
# Change Permissions for the local Administrators group.
$RegKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey( `
"CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}" `
, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree `
, [System.Security.AccessControl.RegistryRights]::ChangePermissions)
$RegACL = $RegKey.GetAccessControl()
$RegRule = New-Object System.Security.AccessControl.RegistryAccessRule( `
"Administrators" `
, "FullControl" `
, "ContainerInherit" `
, "None" `
, "Allow")
$RegACL.SetAccessRule($RegRule)
$RegKey.SetAccessControl($RegACL)
UPDATE related to Another Attempt of Taking the Ownership of that Registry Key:
This is the content of another snippet, called as Change_Registry_Key.2.PS1:
#Define HKCR
New-PSDrive -Name HKCR7 `
-PSProvider Registry `
-Root HKEY_CLASSES_ROOT
#Set $Path HKCR Key Path
$Path = "HKCR:\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}"
#Set $Path Permissions
$ACL = Get-ACL $Path
$Rule = New-Object System.Security.AccessControl.RegistryAccessRule ( `
"<domain>\<username>" `
, "FullControl" `
, "Allow")
$ACL.SetAccessRule($Rule)
$ACL | Set-ACL -Path $path
#Set HKCR 'Attributes' Key Value
Set-ItemProperty -Path $Path `
-Name Attributes `
-Value b0940064
These are the errors that appear in the console area:
PS Y:\> Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.2.PS1
Name Used (GB) Free (GB) Provider Root
---- --------- --------- -------- ----
HKCR7 Registry HKEY_CLASSES_ROOT
Exception calling "SetAccessRule" with "1" argument(s): "Some or all identity refere
nces could not be translated."
At Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.2.PS1
:17 char:1
+ $ACL.SetAccessRule($Rule)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : IdentityNotMappedException
Set-ACL : Requested registry access is not allowed.
At Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.2.PS1
:19 char:8
+ $ACL | Set-ACL -Path $path
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (HKEY_CLASSES_RO...8-08002B30309D}:
String) [Set-Acl], SecurityException
+ FullyQualifiedErrorId : System.Security.SecurityException,Microsoft.PowerShel
l.Commands.SetAclCommand
Set-ItemProperty : Requested registry access is not allowed.
At Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.2.PS1
:22 char:1
+ Set-ItemProperty -Path $Path `
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (HKEY_CLASSES_RO...8-08002B30309D}:
String) [Set-ItemProperty], SecurityException
+ FullyQualifiedErrorId : System.Security.SecurityException,Microsoft.PowerShel
l.Commands.SetItemPropertyCommand
UPDATE Regarding #Theo's Second Version of Renaming the My Computer Desktop Icon:
This version is not working for me yet.
Its testing is quite simple:
I am manually renaming the My Computer Desktop Icon to Fifi;
then I am running this snippet;
then I am manually refreshing the Desktop View.
Although I expect the My Computer Desktop Icon to be renamed back to Work-Laptop, its name still remains fixed as Fifi.
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
#Requires -RunAsAdministrator
Function Enable-Privilege {
[CmdletBinding( ConfirmImpact = 'low'
, SupportsShouldProcess = $false)]
[OutputType('System.Boolean')]
Param(
[Parameter( Mandatory = $true
, Position = 0)]
[ValidateSet( "SeAssignPrimaryTokenPrivilege"
, "SeAuditPrivilege"
, "SeBackupPrivilege"
, "SeChangeNotifyPrivilege"
, "SeCreateGlobalPrivilege"
, "SeCreatePagefilePrivilege"
, "SeCreatePermanentPrivilege"
, "SeCreateSymbolicLinkPrivilege"
, "SeCreateTokenPrivilege"
, "SeDebugPrivilege"
, "SeEnableDelegationPrivilege"
, "SeImpersonatePrivilege"
, "SeIncreaseBasePriorityPrivilege"
, "SeIncreaseQuotaPrivilege"
, "SeIncreaseWorkingSetPrivilege"
, "SeLoadDriverPrivilege"
, "SeLockMemoryPrivilege"
, "SeMachineAccountPrivilege"
, "SeManageVolumePrivilege"
, "SeProfileSingleProcessPrivilege"
, "SeRelabelPrivilege"
, "SeRemoteShutdownPrivilege"
, "SeRestorePrivilege"
, "SeSecurityPrivilege"
, "SeShutdownPrivilege"
, "SeSyncAgentPrivilege"
, "SeSystemEnvironmentPrivilege"
, "SeSystemProfilePrivilege"
, "SeSystemtimePrivilege"
, "SeTakeOwnershipPrivilege"
, "SeTcbPrivilege"
, "SeTimeZonePrivilege"
, "SeTrustedCredManAccessPrivilege"
, "SeUndockPrivilege"
, "SeUnsolicitedInputPrivilege")]
[String]$Privilege
, [Parameter(Position = 1)]
$ProcessId = $PID
, [switch]$Disable
)
Add-Type -TypeDefinition #'
using System;
using System.Runtime.InteropServices;
public class Privilege {
[DllImport( "advapi32.dll"
, ExactSpelling = true
, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(
IntPtr htok
, bool disall
, ref TokPriv1Luid newst
, int len
, IntPtr prev
, IntPtr relen);
[DllImport( "advapi32.dll"
, ExactSpelling = true
, SetLastError = true)]
internal static extern bool OpenProcessToken( IntPtr h
, int acc
, ref IntPtr phtok);
[DllImport( "advapi32.dll"
, SetLastError = true)]
internal static extern bool LookupPrivilegeValue( string host
, string name
, ref long pluid);
[StructLayout( LayoutKind.Sequential
, Pack = 1)]
internal struct TokPriv1Luid {
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool EnablePrivilege( long processHandle
, string privilege
, bool disable) {
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = new IntPtr(processHandle);
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken( hproc
, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
, ref htok);
tp.Count = 1;
tp.Luid = 0;
if(disable) {
tp.Attr = SE_PRIVILEGE_DISABLED;
}
else {
tp.Attr = SE_PRIVILEGE_ENABLED;
}
retVal = LookupPrivilegeValue( null
, privilege
, ref tp.Luid);
retVal = AdjustTokenPrivileges( htok
, false
, ref tp
, 0
, IntPtr.Zero
, IntPtr.Zero);
return retVal;
}
}
'#
try {
$proc = Get-Process -Id $ProcessId -ErrorAction Stop
$name = $proc.ProcessName
$handle = $proc.Handle
$action = if ($Disable) { 'Disabling' } else { 'Enabling' }
Write-Verbose ( "{0} privilege '{1}' for process {2}" -f $action `
, $Privilege `
, $name)
[Privilege]::EnablePrivilege( $handle `
, $Privilege `
, [bool]$Disable)
}
catch {
throw
}
}
################################################################
# Step 1: Give the current process the SeTakeOwnershipPrivilege.
################################################################
$null = Enable-Privilege -Privilege SeTakeOwnershipPrivilege -Verbose
##############################################################
# Step 2: change Owner to the local Administrators group
##############################################################
# Better not use the string "Administrators", because this
# might have a different name in other cultures.
#
# $RegACL.SetOwner([System.Security.Principal.NTAccount]"Administrators")
#
# Use the Well-Known SID instead.
# Local Administrators Group.
$Administrators = `
[System.Security.Principal.SecurityIdentifier]::new('S-1-5-32-544')
$RegKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey( `
"CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}" `
, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree `
, [System.Security.AccessControl.RegistryRights]::TakeOwnership)
$RegACL = $RegKey.GetAccessControl()
$RegACL.SetOwner($Administrators)
$RegKey.SetAccessControl($RegACL)
##############################################################
# Step 3: Give the Local Administrators Group Full Control.
##############################################################
# Refresh the A.C.L.
$RegACL = $RegKey.GetAccessControl()
# Test if there is a Deny rule in the ACL
# for Administrators and, if so, remove that rule.
$RegACL.GetAccessRules( `
$true `
, $true `
, [System.Security.Principal.SecurityIdentifier]) | `
Where-Object { `
$_.AccessControlType -eq 'Deny' `
-and $_.IdentityReference -eq $Administrators.Value `
} | `
ForEach-Object { $null = $RegAcl.RemoveAccessRule($_) }
# Create a new rule allowing the Administrators Full Control.
$RegRule = [System.Security.AccessControl.RegistryAccessRule]::new( `
$Administrators `
, 'FullControl' `
, 'ContainerInherit' `
, 'None' `
, 'Allow')
$RegACL.SetAccessRule($RegRule)
$RegKey.SetAccessControl($RegACL)
# Close the Registry Key.
$RegKey.Close()
##############################################################
# Step 4: Change the 'LocalizedString' property
# in the registry to suit your needs.
##############################################################
#
# With PowerShell 5, you need to use
# `Registry::HKEY_CLASSES_ROOT\..` syntax in order to be able
# to set the registry Type for the value
# with parameter '-Type'.
# As of PowerShell 7, the '-Type' parameter is included.
$RegPath = `
'Registry::HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}'
Set-ItemProperty -Path $RegPath `
-Name 'LocalizedString' `
-Value "%ComputerName%" `
-Type ExpandString `
-Force
What I get in the console is the following text:
PS C:\WINDOWS\system32> C:\Users\MihaiDobrescu\OneDrive\Documents\2_Facturi\12_-_Bank_Services\Digitization\Powershell\Change_Registry_Key.3.PS1 -RunAsAdministrator
VERBOSE: Enabling privilege 'SeTakeOwnershipPrivilege' for process powershell_ise
PS C:\WINDOWS\system32>
UPDATE: A Final Version, with all of the Ingredients of the Beautiful Soup inside of it.
Thanks go again to #Theo who has actually debugged the whole mess.
Note: The snippet is surprisingly working even inside the Virtual Machine, as there is no need for it to be run as an Administrator, since no ownership has to be taken upon the whole Solar System in order to solve this problem.
# How to test:
#
# 1. Rename the My Computer Desktop Icon to "Fifi".
# 2. Remove the My Computer Desktop Icon from the Desktop View.
# 3. Run this snippet.
# 4. Observe how the My Computer Desktop Icon is produced on the Desktop View,
# with the name "Tele-Ordinator" and with a very emotional Desktop Icon.
# Allow the execution of snippets.
Set-ExecutionPolicy `
-ExecutionPolicy RemoteSigned `
-Scope CurrentUser
# Produce the My Computer Desktop Icon on the Desktop View.
# HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel\
# {20D04FE0-3AEA-1069-A2D8-08002B30309D}
# 0 = show
# 1 = hide
$Path = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel"
$Name = "{20D04FE0-3AEA-1069-A2D8-08002B30309D}"
$Exist = "Get-ItemProperty -Path $Path -Name $Name"
if ($Exist)
{
Set-ItemProperty `
-Path $Path `
-Name $Name `
-Value 0
}
Else
{
New-ItemProperty `
-Path $Path `
-Name $Name `
-Value 0
}
# Rename the My Computer Desktop Icon from "This PC" to "Tele-Ordinator".
$My_Computer = 17
$Shell = New-Object -COMObject Shell.Application
$NSComputer = $Shell.Namespace($My_Computer)
$NSComputer.Self.Name = "Tele-Ordinator"
# Change the My Computer Desktop Icon.
$RegPath = `
'Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon'
if (!(Test-Path -Path $RegPath))
{
$null = New-Item `
-Path $RegPath `
-Force
}
Set-ItemProperty `
-Path $RegPath `
-Name '(Default)' `
-Value 'Y:\Digitization\Icons\Robsonbillponte-Happy-Holidays-Pictures.ICO' `
-Type ExpandString `
-Force
# Refresh the Desktop View.
$Definition = #'
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(
int eventId
, int flags
, IntPtr item1
, IntPtr item2);
public static void Refresh()
{
SHChangeNotify(
0x8000000
, 0x1000
, IntPtr.Zero
, IntPtr.Zero);
}
'#
Add-Type `
-MemberDefinition $Definition `
-Namespace WinAPI `
-Name Explorer
[WinAPI.Explorer]::Refresh()
Another Final UPDATE for setting and running a batch file that automates the above automation using the Microsoft Windows Batch Files Preprocessing System:
This is just a short snippet called as Change_Desktop_Icons.BAT.
ChDir %SystemRoot%\System32\WindowsPowerShell\v1.0\
%SystemRoot%\System32\WindowsPowerShell\v1.0\PowerShell.Exe Y:\Digitization\PowerShell\The_My_Computer_Desktop_Icon\Change_Desktop_Icon.PS1
Pause
This is the output of the thing, upon the double-click of its own Desktop Icon.
'\\ISXPFV01.hd00.example.com\us_qv2_dem_user_data_pool_nra$\EE65037.HD00\Desktop'
CMD.EXE was started with the above path as the current directory.
UNC paths are not supported. Defaulting to Windows directory.
C:\Windows>ChDir C:\WINDOWS\System32\WindowsPowerShell\v1.0\
C:\Windows\System32\WindowsPowerShell\v1.0>C:\WINDOWS\System32\WindowsPowerShell\v1.0\PowerShell.Exe Y:\Digitization\PowerShell\The_My_Computer_Desktop_Icon\Change_Desktop_Icon.PS1
C:\Windows\System32\WindowsPowerShell\v1.0>Pause
Press any key to continue . . .
As commented, it is quite a hassle to change the 'Computer' icons caption..
Below code works for me on Windows 10 Pro using PowerShell 5.1
you need run this as Administrator
#Requires -RunAsAdministrator
function Enable-Privilege {
[CmdletBinding(ConfirmImpact = 'low', SupportsShouldProcess = $false)]
[OutputType('System.Boolean')]
Param(
[Parameter(Mandatory = $true, Position = 0)]
[ValidateSet(
"SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege", "SeChangeNotifyPrivilege",
"SeCreateGlobalPrivilege", "SeCreatePagefilePrivilege", "SeCreatePermanentPrivilege",
"SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege", "SeDebugPrivilege", "SeEnableDelegationPrivilege",
"SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege", "SeIncreaseQuotaPrivilege",
"SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege", "SeLockMemoryPrivilege",
"SeMachineAccountPrivilege", "SeManageVolumePrivilege", "SeProfileSingleProcessPrivilege",
"SeRelabelPrivilege", "SeRemoteShutdownPrivilege", "SeRestorePrivilege", "SeSecurityPrivilege",
"SeShutdownPrivilege", "SeSyncAgentPrivilege", "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege",
"SeSystemtimePrivilege", "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege",
"SeTrustedCredManAccessPrivilege", "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
[String]$Privilege,
[Parameter(Position = 1)]
$ProcessId = $PID,
[switch]$Disable
)
Add-Type -TypeDefinition #'
using System;
using System.Runtime.InteropServices;
public class Privilege {
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid {
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool EnablePrivilege(long processHandle, string privilege, bool disable) {
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = new IntPtr(processHandle);
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
if(disable) { tp.Attr = SE_PRIVILEGE_DISABLED; }
else { tp.Attr = SE_PRIVILEGE_ENABLED; }
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
}
'#
try {
$proc = Get-Process -Id $ProcessId -ErrorAction Stop
$name = $proc.ProcessName
$handle = $proc.Handle
$action = if ($Disable) { 'Disabling' } else { 'Enabling' }
Write-Verbose ("{0} privilege '{1}' for process {2}" -f $action, $Privilege, $name)
[Privilege]::EnablePrivilege($handle, $Privilege, [bool]$Disable)
}
catch {
throw
}
}
function Grant-FullControl ([string]$SubKey, [switch]$BreakInheritance) {
# helper function to grant registry FullControl for Administrators on a certain subkey
# better not use the string "Administrators", because this might have a different name in other cultures
# $RegACL.SetOwner([System.Security.Principal.NTAccount]"Administrators")
# use the Well-Known SID instead
$Administrators = [System.Security.Principal.SecurityIdentifier]::new('S-1-5-32-544') # local Administrators group
$RegKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey($SubKey,
[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
[System.Security.AccessControl.RegistryRights]::TakeOwnership)
$RegACL = $RegKey.GetAccessControl()
if ($BreakInheritance) {
# break inheritance, but keep permissions
$RegACL.SetAccessRuleProtection($true, $true)
}
$RegACL.SetOwner($Administrators)
$RegKey.SetAccessControl($RegACL)
# refresh the ACL
$RegACL = $RegKey.GetAccessControl()
# test if there is a Deny rule in the ACL for Administrators and if so remove that rule
$RegACL.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier]) |
Where-Object { $_.AccessControlType -eq 'Deny' -and $_.IdentityReference -eq $Administrators.Value } |
ForEach-Object { $null = $RegAcl.RemoveAccessRule($_) }
# ceate a new rule allowing the Administrators FullControl
$RegRule =[System.Security.AccessControl.RegistryAccessRule]::new($Administrators,
'FullControl',
'ContainerInherit', # ContainerInherit, ObjectInherit
'None', # InheritOnly
'Allow')
$RegACL.SetAccessRule($RegRule)
$RegKey.SetAccessControl($RegACL)
# close the registry key
$RegKey.Close()
}
##################################################################################
# Step 1: give the current process the SeTakeOwnershipPrivilege
##################################################################################
$null = Enable-Privilege -Privilege SeTakeOwnershipPrivilege -Verbose
##################################################################################
# Step 2: change Key Owner to the local Administrators group and grant FullControl
##################################################################################
# first give Administrators full control on key "CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}"
Grant-FullControl -SubKey "CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -BreakInheritance
##################################################################################
# Step 3: change the 'LocalizedString' property in the registry to suit your needs
##################################################################################
# with PowerShell 5 you need to use `Registry::HKEY_CLASSES_ROOT\..` syntax in order to be able
# to set the registry Type for the value with parameter '-Type'.
# As of PowerShell 7 the '-Type' parameter is included
$regPath = 'Registry::HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}'
Set-ItemProperty -Path $regPath -Name 'LocalizedString' -Value "%ComputerName%" -Type ExpandString -Force
##################################################################################
# Step 4: OPTIONAL. Change the Computer icon for NEW user logins
##################################################################################
# give Administrators full control on subkey "CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon"
# now, we do not need to break the inheritance as we needed for the root key
Grant-FullControl -SubKey "CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon"
$regPath = 'Registry::HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon'
Set-ItemProperty -Path $regPath -Name '(Default)' -Value '%SystemRoot%\System32\imageres.dll,-149' -Type ExpandString -Force
##################################################################################
# Step 5: Change the Computer icon for the CURRENT user
##################################################################################
$regPath = 'Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon'
Set-ItemProperty -Path $regPath -Name '(Default)' -Value '%SystemRoot%\System32\imageres.dll,-149' -Type ExpandString -Force
After all this, the desktop doesn't show the computername yet. You need to either press F5 on the desktop, or use the code you found to refresh the desktop.
To change the icon itself, you need to change the default value in registrypath
HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon
for future NEW logins, or registrypath
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon
for the CURRENT user.
By default, it points to %SystemRoot%\System32\imageres.dll,-109, which means it extracts icon no. 109 from the imageres.dll.
In that dll. there are ~343 icons, so you could opt to use another one from the same resource, or take one from another existing dll. (you can use IconsExtract from nirsoft for instance).
I didn't test this yet, but it should also be possible to have it point to the full path and filename of an icon of your own like %SystemDrive%\MyComputerIcon.ico.
As example, this will update the icon to use imageres.dll icon no. 149
$regPath = 'Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon'
Set-ItemProperty -Path $regPath -Name '(Default)' -Value '%SystemRoot%\System32\imageres.dll,-149' -Type ExpandString -Force
which looks like this

Why the argument is empty or null

everyone
I'm a novice at Powershell.
My script gather Windows Event Viewer logs and export data to csv files. If the input is empty then is used the default values.
But it crashes:
"Export-Csv: Unable to validate argument for "Path" parameter. The argument is empty or NULL. Specify a non-empty, non-null argument and then run the command again."
Could explain to me why??
function exportLogs
{
[CmdletBinding()]
param (
$exportFolder=(Read-Host -prompt "exportFolder"),
$applicatiomLogs=(Read-Host -prompt "applicationLogs"),
$systemLogs=(Read-Host -prompt "systemLogs"),
$fromDate=(Read-Host -prompt "fromDate"),
$eventTypes=(Read-Host -prompt "eventTypes")
)
$comp = $env:computername
$now=Get-Date
#check empty input and assign default values
if (!$exportFolder) { [String]$exportFolder="D:\temp\" }
if (!$applicationLogs) {
$applicationLogs="True"
[System.Convert]::ToBoolean($applicationLogs)
}
if (!$systemLogs) {
$systemLogs="True"
[System.Convert]::ToBoolean($systemLogs)
}
if (!$fromDate) { [DateTime]$fromDate=$now.AddDays(-30) }
if (!$eventtypes) { [String[]]$eventtypes=("Error", "Warning") }
if ($applicationLogs)
{
$exportFile = $exportFolder + "applicationLogs_" + $now.ToString("yyyyMMddHHmmss") + ".csv"
$exportedLog = get-eventlog -ComputerName $comp -log "Application" -After $fromDate -EntryType $eventTypes
exportCsv($exportedLog, $exportFile)
}
if ($systemLogs)
{
$exportFile = $exportFolder + "systemLogs_" + $now.ToString("yyyyMMddHHmmss") + ".csv"
$exportedLog = get-eventlog -ComputerName $comp -log "System" -After $fromDate -EntryType $eventTypes
exportCsv($exportedLog, $exportFile)
}
}
function exportCsv([String]$exportedLog, [String]$exportFile)
{
$el_sorted = $exportedLog | Sort-Object TimeGenerated
Write-Host Exporting to $exportFile
$el_sorted|Select MachineName, TimeGenerated, EntryType, Source, Message | Export-CSV $exportFile -NoTypeInfo
}
Try this refactor... (run on the default Windows Sandbox on Win10)
function New-LogExport
{
Param
(
[String]$exportedLog,
[String]$exportFile
)
$el_sorted = $exportedLog |
Sort-Object TimeGenerated
Write-Host "Exporting to $exportFile"
$el_sorted |
Select-Object MachineName,
TimeGenerated,
EntryType,
Source,
Message |
Export-Csv -Path $exportFile -NoTypeInfo
}
function Start-ExportLogs
{
[CmdletBinding()]
param
(
$exportFolder = (Read-Host -prompt 'exportFolder'),
$applicatiomLogs = (Read-Host -prompt 'applicationLogs'),
$systemLogs = (Read-Host -prompt 'systemLogs'),
$fromDate = (Read-Host -prompt 'fromDate'),
$eventTypes = (Read-Host -prompt 'eventTypes')
)
$comp = $env:computername
$now = Get-Date
if (!$exportFolder)
{[String]$exportFolder = 'C:\temp'}
if (!$applicationLogs)
{
$applicationLogs = 'True'
[System.Convert]::ToBoolean($applicationLogs)
}
if (!$systemLogs)
{
$systemLogs = 'True'
[System.Convert]::ToBoolean($systemLogs)
}
if (!$fromDate)
{[DateTime]$fromDate = $now.AddDays(-30)}
if (!$eventtypes)
{[String[]]$eventtypes = ('Error', 'Warning')}
if ($applicationLogs)
{
$exportFile = "$exportFolder\applicationLogs_$($now.ToString('yyyyMMddHHmmss')).csv"
$getEventLogSplat = #{
ComputerName = $comp
LogName = 'Application'
EntryType = $eventTypes
After = $fromDate
}
$exportedLog = Get-EventLog #getEventLogSplat
New-LogExport -exportedLog $exportedLog, -exportFile $exportFile
}
if ($systemLogs)
{
$exportFile = "$exportFolder\systemLogs_$($now.ToString('yyyyMMddHHmmss')).csv"
$getEventLogSplat = #{
ComputerName = $comp
LogName = 'System'
EntryType = $eventTypes
After = $fromDate
}
$exportedLog = Get-EventLog #getEventLogSplat
}
New-LogExport -exportedLog $exportedLog -exportFile $exportFile
}
# Results
<#
exportFolder:
applicationLogs:
systemLogs:
fromDate:
eventTypes:
True
True
Exporting to C:\temp\applicationLogs_20210120143659.csv
Exporting to C:\temp\systemLogs_20210120143659.csv
#>

Server Pending Reboot

I am trying to modify my PowerShell script to find the best possible ways to check for Pending Reboots on our servers. This script checks the registry entries. However, I am seeing inconsistencies from other PowerShell scripts and wanting guidance on the best approach.
function PendingReboot ($comp) {
process {
try {
$WMI_OS = ""
$RegCon = ""
$WMI_OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $comp -ErrorAction Stop
if ($?){
try{
$RegCon = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"LocalMachine",$comp)
If ($WMI_OS.BuildNumber -ge 6001){
$RegValueSetupex = ""
$RegValuePFRO2k8 = ""
$RegSubKeySM = $RegCon.OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\")
$RegValueSetupex = $RegSubKeySM.GetValue("SetupExecute",$null)
if ($RegValueSetupex){
$RegValueSetupex = $true
}
$RegSubKeySM = $RegCon.OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\")
$RegValuePFRO2k8 = $RegSubKeySM.GetValue("PendingFileRenameOperations",$null)
if ($RegValuePFRO2k8 ){
$RegValuePFRO2k8 = $true
}
$RegCon.Close()
if ( $RegValueSetupex -eq $true -or $RegValuePFRO2k8 -eq $true){
return '<font color="#FF0000">'+$true
}
else {
return $false
}
}
else{
$RegValuePFRO2k3 = $false;
$RegCon = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"LocalMachine","$comp")
$RegSubKeySM = $RegCon.OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\")
$RegValuePFRO2k3 = $RegSubKeySM.GetValue("PendingFileRenameOperations",$null)
$RegCon.Close()
If ($RegValuePFRO2k3) {
return '<font color="#FF0000">'+$true;
}
else {
return $false;
}
}
}
catch {
return '<font color="#FFFF00">'+"Remote Registry Service KO"
}
}
else {
throw $error[0].Exception
}
}
catch {
return '<font color="#FF0000">'+"RPC Issue"
}
}
}
Try this.
function PendingBoot($comp) {
$pendingRebootTests = #(
#{
Name = 'RebootPending'
Test = { Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing' Name 'RebootPending' -ErrorAction Ignore }
TestType = 'ValueExists'
}
#{
Name = 'RebootRequired'
Test = { Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update' Name 'RebootRequired' -ErrorAction Ignore }
TestType = 'ValueExists'
}
#{
Name = 'PendingFileRenameOperations'
Test = { Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' -Name 'PendingFileRenameOperations' -ErrorAction Ignore }
TestType = 'NonNullValue'
}
)
$session = New-PSSession -Computer SRV1
foreach ($test in $pendingRebootTests) {
$result = Invoke-Command -Session $session -ScriptBlock $test.Test
if ($test.TestType -eq 'ValueExists' -and $result) {
$true
} elseif ($test.TestType -eq 'NonNullValue' -and $result -and $result.($test.Name)) {
$true
} else {
$false
}
}
$session | Remove-PSSession
}

Powershell is failing with named instance in connection string

function Get-Type {
param($type)
$types = #( 'System.Boolean', 'System.Byte[]', 'System.Byte', 'System.Char', 'System.Datetime', 'System.Decimal',
'System.Double', 'System.Guid', 'System.Int16', 'System.Int32',
'System.Int64', 'System.Single', 'System.UInt16', 'System.UInt32',
'System.UInt64')
if ( $types -contains $type )
{
Write-Output "$type"
}
else
{
Write-Output 'System.String'
}
}
function Out-DataTable {
[CmdletBinding()]
param([Parameter(Position=0, Mandatory=$true, ValueFromPipeline = $true)] [PSObject[]]$InputObject)
Begin
{
$dt = new-object Data.datatable
$First = $true
}
Process
{
foreach ($object in $InputObject)
{
$DR = $DT.NewRow()
foreach($property in $object.PsObject.get_properties())
{
if ($first)
{
$Col = new-object Data.DataColumn
$Col.ColumnName = $property.Name.ToString()
if ($property.value)
{
if ($property.value -isnot [System.DBNull])
{
$Col.DataType = [System.Type]::GetType("$(Get-Type $property.TypeNameOfValue)")
}
}
$DT.Columns.Add($Col)
}
if ($property.IsArray)
{
$DR.Item($property.Name) =$property.value | ConvertTo-XML -AS String -NoTypeInformation -Depth 1
}
else
{
$DR.Item($property.Name) = $property.value
}
}
$DT.Rows.Add($DR)
$First = $false
}
}
End
{
Write-Output #(,($dt))
}
}
try
{
add-type -AssemblyName "Microsoft.SqlServer.ConnectionInfo, Version=10.0.0.0,
Culture=neutral, PublicKeyToken=89845dcd8080cc91" -EA Stop} catch
{add-type -AssemblyName "Microsoft.SqlServer.ConnectionInfo"} try
{add-type -AssemblyName "Microsoft.SqlServer.Smo, Version=10.0.0.0,
Culture=neutral, PublicKeyToken=89845dcd8080cc91" -EA Stop} catch
{add-type -AssemblyName "Microsoft.SqlServer.Smo"
}
function Get-SqlType
{
param([string]$TypeName)
switch ($TypeName)
{
'Boolean' {[Data.SqlDbType]::Bit}
'Byte[]' {[Data.SqlDbType]::VarBinary}
'Byte' {[Data.SQLDbType]::VarBinary}
'Datetime' {[Data.SQLDbType]::DateTime}
'Decimal' {[Data.SqlDbType]::Decimal}
'Double' {[Data.SqlDbType]::Float}
'Guid' {[Data.SqlDbType]::UniqueIdentifier}
'Int16' {[Data.SQLDbType]::SmallInt}
'Int32' {[Data.SQLDbType]::Int}
'Int64' {[Data.SqlDbType]::BigInt}
'UInt16' {[Data.SQLDbType]::SmallInt}
'UInt32' {[Data.SQLDbType]::Int}
'UInt64' {[Data.SqlDbType]::BigInt}
'Single' {[Data.SqlDbType]::Decimal}
default {[Data.SqlDbType]::VarChar}
}
}
function Add-SqlTable
{
[CmdletBinding()]
param(
[Parameter(Position=0, Mandatory=$true)] [string]$ServerInstance,
[Parameter(Position=1, Mandatory=$true)] [string]$Database,
[Parameter(Position=2, Mandatory=$true)] [String]$TableName,
[Parameter(Position=3, Mandatory=$true)] [System.Data.DataTable]$DataTable,
[Parameter(Position=4, Mandatory=$false)] [string]$Username,
[Parameter(Position=5, Mandatory=$false)] [string]$Password,
[ValidateRange(0,8000)]
[Parameter(Position=6, Mandatory=$false)] [Int32]$MaxLength=1000,
[Parameter(Position=7, Mandatory=$false)] [switch]$AsScript
)
try
{
if($Username)
{
$con = new-object ("Microsoft.SqlServer.Management.Common.ServerConnection") $ServerInstance,$Username,$Password
}
else
{
$con = new-object ("Microsoft.SqlServer.Management.Common.ServerConnection") $ServerInstance
}
$con.Connect()
$server = new-object ("Microsoft.SqlServer.Management.Smo.Server") $con
$db = $server.Databases[$Database]
$table = new-object ("Microsoft.SqlServer.Management.Smo.Table") $db, $TableName
foreach ($column in $DataTable.Columns)
{
$sqlDbType = [Microsoft.SqlServer.Management.Smo.SqlDataType]"$(Get-SqlType $column.DataType.Name)"
if ($sqlDbType -eq 'VarBinary' -or $sqlDbType -eq 'VarChar')
{
if ($MaxLength -gt 0)
{
$dataType = new-object ("Microsoft.SqlServer.Management.Smo.DataType") $sqlDbType, $MaxLength
}
else
{
$sqlDbType = [Microsoft.SqlServer.Management.Smo.SqlDataType]"$(Get-SqlType $column.DataType.Name)Max"
$dataType = new-object ("Microsoft.SqlServer.Management.Smo.DataType") $sqlDbType
}
}
else
{
$dataType = new-object ("Microsoft.SqlServer.Management.Smo.DataType") $sqlDbType
}
$col = new-object ("Microsoft.SqlServer.Management.Smo.Column") $table, $column.ColumnName, $dataType
$col.Nullable = $column.AllowDBNull
$table.Columns.Add($col)
}
if ($AsScript) {
$table.Script()
}
else
{
$table.Create()
}
}
catch
{
$message = $_.Exception.GetBaseException().Message
Write-Error $message
}
}
function Write-DataTable
{
[CmdletBinding()]
param(
[Parameter(Position=0, Mandatory=$true)] [string]$ServerInstance,
[Parameter(Position=1, Mandatory=$true)] [string]$Database,
[Parameter(Position=2, Mandatory=$true)] [string]$TableName,
[Parameter(Position=3, Mandatory=$true)] $Data,
[Parameter(Position=4, Mandatory=$false)] [string]$Username,
[Parameter(Position=5, Mandatory=$false)] [string]$Password,
[Parameter(Position=6, Mandatory=$false)] [Int32]$BatchSize=50000,
[Parameter(Position=7, Mandatory=$false)] [Int32]$QueryTimeout=0,
[Parameter(Position=8, Mandatory=$false)] [Int32]$ConnectionTimeout=15
)
$conn=new-object System.Data.SqlClient.SQLConnection($Username)
{
$ConnectionString = "Server={0};Database={1};User ID={2};Password={3};Trusted_Connection=False;Connect Timeout={4}" -f $ServerInstance,$Database,$Username,$Password,$ConnectionTimeout
}
else
{
$ConnectionString = "Server={0};Database={1};Integrated Security=True;Connect Timeout={2}" -f $ServerInstance,$Database,$ConnectionTimeout
}
$conn.ConnectionString=$ConnectionString
try
{
$conn.Open()
$bulkCopy = new-object ("Data.SqlClient.SqlBulkCopy") $connectionString
$bulkCopy.DestinationTableName = $tableName
$bulkCopy.BatchSize = $BatchSize
$bulkCopy.BulkCopyTimeout = $QueryTimeOut
$bulkCopy.WriteToServer($Data)
$conn.Close()
}
catch
{
$ex = $_.Exception
Write-Error "$ex.Message"
continue
}
}
$xmlfile = [xml](get-content "C:\SQLConfiguration.XML") set-location $xmlfile.configuration.folders.APP.Path
$servername=$xmlfile.configuration.server.servername
foreach ($svr in get-content C:\justservers.txt) {
$dt = new-object "System.Data.DataTable"
$cn = new-object System.Data.SqlClient.SqlConnection "server=$svr;database=master;Integrated Security=sspi"
$cn.Open()
$sql = $cn.CreateCommand()
$sql.CommandText = "select * from blah"
The above code is working for default instance but not named instance.
Justserver.txt file has both default and named instances like below
xxxxx xxxx\ins01 xxx\ins02
I am hitting error for xxxx\ins01 as "Exception calling execute reader with 0 arguments" string or binary data would be truncated"
any help is appreciated
regards,
Is the backslash before the instance name being seen as an escape character? Try using a replace in your code to escape the escape, something like this:
$svr = $svr -replace '\\', '\\'
$cn = new-object System.Data.SqlClient.SqlConnection "server=$svr;database=master;Integrated Security=sspi"
$cn.Open()
There is no problem with Powershell but I found one of coloumn length was not ok with the data populated. I have fixed it now and got result as expected. Thanks you all and have a great weekend

Get free disk space for different servers with separate credentials

I'm trying to query Disk space info on Grid box and Export it to CSV.
I was able to use Marc Weisel's script to make it use different credentials. I used computers.csv
to store the computer name and referenced credentials. This is working although the problem I'm facing is that Grid box opens for all the servers mentioned in the csv.
I want to view all disk space information on the same grid box.
Below are my script and module I'm using
Import-Module D:\get.psm1
Import-Module D:\out-CSV.psm1
$ComputerList = Import-Csv -Path d:\Computers.csv;
#$servers = 'laptop-pc','laptop-pc','laptop-pc'
$CredentialList = #{
Cred1 = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList 'laptop-pc\laptop', (ConvertTo-SecureString -String 'tamboli' -AsPlainText -Force);
#Cred2 = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList 'tnt\administrator', (ConvertTo-SecureString -String 'Atlantic12' -AsPlainText -Force);
}
foreach ($computer in $ComputerList )
{
Get-DiskFree -ComputerName $Computer.Name -Credential $CredentialList[$Computer.Credential] -Format | ? { $_.Type -like '*fixed*' } | select * -ExcludeProperty Type |
}
get.ps1
function Get-DiskFree
{
[CmdletBinding()]
param
(
[Parameter(Position=0,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[Alias('hostname')]
[Alias('cn')]
[string[]]$ComputerName = $env:COMPUTERNAME,
[Parameter(Position=1,
Mandatory=$false)]
[Alias('runas')]
[System.Management.Automation.Credential()]$Credential =
[System.Management.Automation.PSCredential]::Empty,
[Parameter(Position=2)]
[switch]$Format
)
BEGIN
{
function Format-HumanReadable
{
param ($size)
switch ($size)
{
{$_ -ge 1PB}{"{0:#.#'P'}" -f ($size / 1PB); break}
{$_ -ge 1TB}{"{0:#.#'T'}" -f ($size / 1TB); break}
{$_ -ge 1GB}{"{0:#.#'G'}" -f ($size / 1GB); break}
{$_ -ge 1MB}{"{0:#.#'M'}" -f ($size / 1MB); break}
{$_ -ge 1KB}{"{0:#'K'}" -f ($size / 1KB); break}
default {"{0}" -f ($size) + "B"}
}
}
$wmiq = 'SELECT * FROM Win32_LogicalDisk WHERE Size != Null AND DriveType >= 2'
}
PROCESS
{
foreach ($computer in $ComputerName)
{
try
{
if ($computer -eq $env:COMPUTERNAME)
{
$disks = Get-WmiObject -Query $wmiq `
-ComputerName $computer -ErrorAction Stop
}
else
{
$disks = Get-WmiObject -Query $wmiq `
-ComputerName $computer -Credential $Credential `
-ErrorAction Stop
}
if ($Format)
{
# Create array for $disk objects and then populate
$diskarray = #()
$disks | ForEach-Object { $diskarray += $_ }
$diskarray | Select-Object #{n='Name';e={$_.SystemName}},
#{n='Vol';e={$_.DeviceID}},
#{n='Size';e={Format-HumanReadable $_.Size}},
#{n='Used';e={Format-HumanReadable `
(($_.Size)-($_.FreeSpace))}},
#{n='Avail';e={Format-HumanReadable $_.FreeSpace}},
#{n='Use%';e={[int](((($_.Size)-($_.FreeSpace))`
/($_.Size) * 100))}},
#{n='FS';e={$_.FileSystem}},
#{n='Type';e={$_.Description}}
}
else
{
foreach ($disk in $disks)
{
$diskprops = #{'Volume'=$disk.DeviceID;
'Size'=$disk.Size;
'Used'=($disk.Size - $disk.FreeSpace);
'Available'=$disk.FreeSpace;
'FileSystem'=$disk.FileSystem;
'Type'=$disk.Description
'Computer'=$disk.SystemName;}
# Create custom PS object and apply type
$diskobj = New-Object -TypeName PSObject `
-Property $diskprops
$diskobj.PSObject.TypeNames.Insert(0,'BinaryNature.DiskFree')
Write-Output $diskobj
}
}
}
catch
{
# Check for common DCOM errors and display "friendly" output
switch ($_)
{
{ $_.Exception.ErrorCode -eq 0x800706ba } `
{ $err = 'Unavailable (Host Offline or Firewall)';
break; }
{ $_.CategoryInfo.Reason -eq 'UnauthorizedAccessException' } `
{ $err = 'Access denied (Check User Permissions)';
break; }
default { $err = $_.Exception.Message }
}
Write-Warning "$computer - $err"
}
}
}
END {}
}
You need to append the result of Get-DiskFree to an array in the loop, and pipe that result to the Grid View from outside your loop:
foreach ($computer in $ComputerList )
{
$result += Get-DiskFree -ComputerName $Computer.Name -Credential $CredentialList[$Computer.Credential] -Format | ? { $_.Type -like '*fixed*' } | select * -ExcludeProperty Type
}
$result | Out-GridView
Or, better yet, pipe the result from outside the Foreach-Object loop:
$ComputerList | % {
Get-DiskFree -ComputerName $_.Name -Credential $CredentialList[$_.Credential] -Format | ? { $_.Type -like '*fixed*' } | select * -ExcludeProperty Type
} | Out-GridView

Resources