Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- [Console]::OutputEncoding = [System.Text.Encoding]::UTF8; $ErrorActionPreference = 'Stop'; $WarningPreference = 'SilentlyContinue'; $ConfirmPreference = 'None'; $ProgressPreference = 'SilentlyContinue'; ${A1_Agent_Exe_Path}="C:\Windows\Action1\action1_agent.exe"; ${A1_Agent}="$true"; ${A1_OutProc}="$true"; { try { $output = "" | Select-Object User, 'CPU Model', 'CPU Size', RAM, Disk, Video, NIC, WiFi, 'Motherboard Vendor', 'BIOS Serial', 'Reboot Required', 'CPU Name', 'CPU Data Width', 'CPU Manufacturer', 'CPU Status', 'CPU Error Description',
- 'Motherboard Product', 'Motherboard Version', 'Motherboard Tag', 'System Manufacturer', 'System Model', 'System Type', 'BIOS Manufacturer', 'SMBIOS BIOS Version', 'BIOS Software Element State', 'BIOS Version', 'RAM Type', 'Last Boot Time', OU, 'AD Security Groups', A1_Key;
- #
- #Options
- #
- #systemInfoBootTime = true: read LastBootUpTime from systeminfo; false: read the timestamp of the newest 6005 event.
- $systemInfoBootUpTime = $true;
- #
- # CPU Info
- #
- try {
- $proc = (Get-WmiObject Win32_Processor)
- $proc0 = if ( $proc -is [array] ) { $proc[0] } else { $proc; }
- $cpu_count = if ( $proc -is [array] ) { $proc.count } else { 1; }
- $output.'CPU Name' = $proc0.Name;
- $output.'CPU Model' = $($proc0.Caption);
- $output.'CPU Data Width' = $($proc0.DataWidth);
- $CPUSpeed = [math]::Round($proc0.MaxClockSpeed / 1000 + 0.005, 2); # the above rounds up to 0.01
- $output.'CPU Size' = "$($cpu_count)x$CPUSpeed GHz, $($proc0.NumberOfCores)/$($proc0.NumberOfLogicalProcessors) Cores"
- $output.'CPU Manufacturer' = $proc0.Manufacturer;
- $output.'CPU Status' = switch ($proc0.CPUStatus) {
- 1 { 'CPU Enabled' } 2 { 'CPU Disabled by User via BIOS Setup' } 3 { 'CPU Disabled By BIOS (POST Error)' } 4 { 'CPU is Idle' } 5 { 'Reserved' } 6 { 'Reserved' } 7 { 'Other' } default { 'Unknown' }
- }
- $output.'CPU Error Description' = $proc0.ErrorDescription;
- }
- catch {}
- #
- # RAM Info
- #
- try {
- $ram = Get-WmiObject Win32_PhysicalMemory;
- $total_RAM_size = [Int64]0;
- $ram.Capacity | ForEach-Object { $total_RAM_size += [Int64]$_ };
- $rounding = if ( $total_RAM_size -lt 1Gb ) { 2 } else { 0 };
- $RAMSize = [math]::Round($total_RAM_size / 1Gb, $rounding);
- $ram0 = if ( $ram -is [array] ) { $ram[0] } else { $ram };
- $RAMType = switch ($ram0.SMBIOSMemoryType) {
- 1 { 'Other' } 2 { 'DRAM' } 3 { 'Synch DRAM' } 4 { 'Cache DRAM' } 5 { 'EDO' } 6 { 'EDRAM' } 7 { 'VRAM' } 8 { 'SRAM' } 9 { 'RAM' } 10 { 'ROM' } 11 { 'Flash' } 12 { 'EEPROM' }
- 13 { 'FEPROM' } 14 { 'EPROM' } 15 { 'CDRAM' } 16 { '3DRAM' } 17 { 'SDRAM' } 18 { 'SGRAM' } 19 { 'RDRAM' } 20 { 'DDR' } 21 { 'DDR2' } 22 { 'DDR2 FB-DIMM' } 24 { 'DDR3' }
- 25 { 'FBD2' } 26 { 'DDR4' } default { 'Unknown' }
- }
- $output.RAM = "$($RAMSize)Gb $RAMType"
- $RAMFormFactorList = @{};
- $ram | ForEach-Object {
- $RAMType = switch ($_.FormFactor) {
- 1 { 'Other' } 2 { 'SIP' } 3 { 'DIP' } 4 { 'ZIP' } 5 { 'SOJ' } 6 { 'Proprietary' } 7 { 'SIMM' } 8 { 'DIMM' } 9 { 'TSOP' } 10 { 'PGA' } 11 { 'RIMM' } 12 { 'SODIMM' }
- 13 { 'SRIMM' } 14 { 'SMD' } 15 { 'SSMP' } 16 { 'QFP' } 17 { 'TQFP' } 18 { 'SOIC' } 19 { 'LCC' } 20 { 'PLCC' } 21 { 'BGA' } 22 { 'FPBGA' } 23 { 'LGA' } default { 'Unknown' }
- }
- if ($RAMFormFactorList.$RAMType) {
- $RAMFormFactorList.$RAMType = $RAMFormFactorList.$RAMType + 1;
- }
- else {
- $RAMFormFactorList.add( $RAMType, 1 );
- }
- }
- $output.'RAM Type' = ($RAMFormFactorList.keys | ForEach-Object {
- Write-Output "$($_) x $([int]$RAMFormFactorList.$_)";
- }) -join ', ';
- if (!$output.'RAM Type') {
- $output.'RAM Type' = 'Unknown';
- }
- }
- catch {}
- #
- # Disk Info
- #
- try {
- function getRoundingRange ([UInt64]$size) {
- $rounding = if ( $_.Size -lt 1Gb ) { 2 } else { 0 };
- return $rounding;
- }
- try {
- $disks = Get-WmiObject MSFT_PhysicalDisk -Namespace "root/microsoft/windows/storage" -Filter "BusType <> '7' and BusType <> '12' and BusType <> '13'" -ErrorAction Stop | Sort-Object -Property __PATH
- # NOTE: BusType <> 7, 12, 13 - excludes USB drives, secure digital (SD) and multimedia cards
- $output.Disk = ($disks | ForEach-Object {
- $DiskSize = [math]::Round($_.Size / 1Gb, (getRoundingRange($_.Size)));
- $DiskType = switch ($_.MediaType) { 3 { 'HDD' } 4 { 'SSD' } 5 { 'SCM' } default { 'Generic' } }
- Write-Output "$($DiskSize)Gb $DiskType";
- }) -join ', ';
- }
- catch {
- # not supported - older version of Windows - try older way
- $disks = Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType = '3'" | Sort-Object -Property __PATH
- # NOTE: DriveType = '3' is Local Disk (not removable, not network etc)
- $output.Disk = ($disks | ForEach-Object {
- $DiskSize = [math]::Round($_.Size / 1Gb, (getRoundingRange($_.Size)));
- Write-Output "$($DiskSize)Gb Generic";
- }) -join ', ';
- }
- }
- catch {}
- #
- # GPU Info
- #
- try {
- $video = Get-WmiObject Win32_VideoController | Sort-Object -Property Name
- $output.Video = ($video | ForEach-Object {
- $VideoRAM = [Int64]($_.AdapterRAM / 1GB)
- Write-Output "$($_.Caption), $($_.AdapterDACType), $($VideoRAM)Gb"
- }) -join ', ';
- }
- catch {}
- #
- # Network Info
- #
- function isPhysical([string]$nicName) {
- $physicalNICs = Get-WmiObject -Class Win32_NetworkAdapter | Where-Object { $_.PhysicalAdapter -eq $true -and $_.PNPDeviceID -notlike 'ROOT\*' };
- foreach ($physicalNIC in $physicalNICs) {
- if ($physicalNIC.Name -eq $nicName) {
- return $true;
- }
- }
- }
- try {
- $wifis = Get-WmiObject -Namespace ROOT\WMI -Class MSNdis_PhysicalMediumType | Where-Object { $_.NdisPhysicalMediumType -eq 9 } | Sort-Object -Property InstanceName
- $eths = Get-WmiObject -Namespace ROOT\WMI -Class MSNdis_PhysicalMediumType | Where-Object { $_.NdisPhysicalMediumType -eq 0 } | Sort-Object -Property InstanceName
- $output.WiFi = ($wifis | ForEach-Object {
- if (isPhysical($_.InstanceName)) {
- Write-Output "$($_.InstanceName)"
- }
- }) -join ', ';
- $output.NIC = ($eths | ForEach-Object {
- if (isPhysical($_.InstanceName)) {
- Write-Output "$($_.InstanceName)"
- }
- }) -join ', ';
- }
- catch {}
- #
- # MB Info
- #
- try {
- $MB = Get-WmiObject Win32_BaseBoard;
- $output.'Motherboard Vendor' = if ($MB.Manufacturer) { $MB.Manufacturer } else { 'Unknown' };
- $output.'Motherboard Product' = if ($MB.Product) { $MB.Product } else { 'Unknown' };
- $output.'Motherboard Version' = if ($MB.Version) { $MB.Version } else { 'Unknown' };
- $output.'Motherboard Tag' = if ($MB.Tag) { $MB.Tag } else { 'Unknown' };
- }
- catch {}
- #
- # System Info
- #
- try {
- $CS = Get-WMIObject Win32_ComputerSystem;
- $output.'System Manufacturer' = $CS.Manufacturer;
- $output.'System Model' = $CS.Model;
- $output.'System Type' = $CS.SystemType;
- }
- catch {}
- #
- # User Info
- #
- function GetCurrentUser {
- $currentUser = "None"
- $previousUser = "None"
- $previousFile = "$env:windir\Action1\previousUser.txt"
- if (-not([string]::IsNullOrEmpty($A1_Agent_Exe_Path))) {
- $currentUser = & $A1_Agent_Exe_Path loggedonuser
- }
- else {
- $logonEvents = Get-WinEvent -FilterHashtable @{Logname = 'Security'; ID = 4624 } -MaxEvents 1000 -ErrorAction SilentlyContinue | Where-Object { $lt = $_.Properties[8].Value; $cn = $_.Properties[6].Value; ($lt -eq "2" -or $lt -eq "7" -or $lt -eq "10" -or $lt -eq "11") -and ($cn -ne 'Window Manager' -and $cn -ne 'Font Driver Host') }
- $logonEvent = $logonEvents | Select-Object -First 1
- try {
- $sid = New-Object System.Security.Principal.SecurityIdentifier($logonEvent.Properties[4].Value)
- $currentUser = $sid.Translate([System.Security.Principal.NTAccount]).Value
- }
- catch {
- if ($null -ne $logonEvent) {
- $currentUser = "$($logonEvent.Properties[6].Value)\$($logonEvent.Properties[5].Value)"
- }
- }
- }
- try {
- if (Test-Path -Path $previousFile -PathType Leaf) {
- $previousUser = Get-Content -Path $previousFile -ErrorAction SilentlyContinue
- }
- }
- catch {}
- if ($currentUser -eq "None" -and -not([string]::IsNullOrEmpty($previousUser))) {
- $currentUser = $previousUser
- }
- try {
- if ($previousUser -ne $currentUser) {
- New-Item -Path $previousFile -ItemType File -Value $currentUser -Force -ErrorAction Stop | Out-Null
- }
- }
- catch {}
- return $currentUser
- }
- $output.User = GetCurrentUser;
- #
- # BIOS Info
- #
- try {
- $BIOS = Get-WMIObject Win32_BIOS;
- $output.'BIOS Manufacturer' = $BIOS.Manufacturer;
- $output.'SMBIOS BIOS Version' = $BIOS.SMBIOSBIOSVersion;
- $output.'BIOS Software Element State' = switch ($BIOS.SoftwareElementState) { 0 { 'Deployable' } 1 { 'Installable' } 2 { 'Executable' } 3 { 'Running' } default { 'unknown' } };
- $output.'BIOS Version' = $BIOS.Version;
- $output.'BIOS Serial' = $BIOS.SerialNumber;
- }
- catch {}
- #
- # Reboot Status
- #
- function Test-RegistryKey ([string]$Key) {
- try {
- $keyExist = Test-Path -Path $Key -ErrorAction Stop;
- }
- catch {
- $keyExist = $false;
- }
- Write-Output $keyExist;
- }
- function Test-RegistryValueNotNull ([string]$Key, [string]$Value) {
- $valueNotNull = $false;
- try {
- if ((Test-Path -Path $Key -ErrorAction Stop) -and ($regVal = Get-ItemProperty -Path $Key -Name $Value -ErrorAction Stop) -and $regVal.($Value)) {
- $valueNotNull = $true;
- }
- }
- catch {}
- Write-Output $valueNotNull;
- }
- function Get-RegistryValueSafe ([string]$Key, [string]$Value) {
- $valueSafe = $null;
- try {
- if (Test-Path -Path $Key -ErrorAction Stop) {
- $valueSafe = Get-ItemProperty -Path $Key -ErrorAction Stop | Select-Object -ExpandProperty $Value -ErrorAction Stop;
- }
- }
- catch {}
- Write-Output $valueSafe;
- }
- #
- # Reboot Info
- #
- try {
- $rebootPending = Test-RegistryKey -Key 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending';
- # $rebootInProgress = Test-RegistryKey -Key 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress';
- # $packagesPending = Test-RegistryKey -Key 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackagesPending';
- $rebootRequired = Test-RegistryKey -Key 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired';
- # $postRebootReporting = Test-RegistryKey -Key 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\PostRebootReporting';
- # $pendingFileRenameOperations = Test-RegistryValueNotNull -Key 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' -Value 'PendingFileRenameOperations';
- # $pendingFileRenameOperations2 = Test-RegistryValueNotNull -Key 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' -Value 'PendingFileRenameOperations2';
- $joinDomain = Test-RegistryKey -Key 'HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\JoinDomain';
- $avoidSpnSet = Test-RegistryKey -Key 'HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\AvoidSpnSet';
- # $updateExeVolatile = ($uev = Get-RegistryValueSafe -Key 'HKLM:\SOFTWARE\Microsoft\Updates' -Value 'UpdateExeVolatile') -and ($uev -ne 0);
- $computerNameChanged = ( Get-RegistryValueSafe -Key 'HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName' -Value 'ComputerName' ) -ne ( Get-RegistryValueSafe -Key 'HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName' -Value 'ComputerName' );
- if ( $rebootPending -or $rebootInProgress -or $packagesPending -or $rebootRequired -or $postRebootReporting -or $pendingFileRenameOperations -or
- $pendingFileRenameOperations2 -or $joinDomain -or $avoidSpnSet -or $updateExeVolatile -or $computerNameChanged) {
- $output.'Reboot Required' = "Yes";
- }
- else {
- $output.'Reboot Required' = "No";
- }
- }
- catch {}
- #
- # Last Boot Up Time
- #
- try {
- $bootDateTime = $null;
- if ($systemInfoBootUpTime)
- {
- $lastBootUpTime = Get-WmiObject Win32_OperatingSystem | Select-Object @{Name='LastBootUpTime'; Expression={$_.ConverttoDateTime($_.LastBootUpTime)}};
- $bootDateTime = $lastBootUpTime.LastBootUpTime;
- }
- else {
- $startupEvent = Get-WinEvent -LogName 'System' -MaxEvents 1 -FilterXPath "<QueryList><Query Id='0' Path='System'><Select Path='System'>*[System[(EventID=6005)]]</Select></Query></QueryList>";
- $bootDateTime = $startupEvent.TimeCreated;
- }
- $lastBootTimeUtc = $bootDateTime.ToUniversalTime();
- $formattedBootTime = Get-Date -Date $lastBootTimeUtc -Format 'yyyy-MM-dd_HH-mm-ss';
- $output.'Last Boot Time' = $formattedBootTime;
- }
- catch {}
- function Convert-DNToCanonicalName {
- param (
- [string]$DistinguishedName
- )
- $parts = $DistinguishedName -split '(?<!\\),';
- $unescapedParts = $parts -replace '\\(?!\\)', '';
- $canonicalNameComponents = @();
- $DCComponents = @();
- $cnSpecialSymbols = '([\\\/])';
- for ($i = $unescapedParts.Length - 1; $i -gt 0; $i--) {
- $component = $unescapedParts[$i].Trim();
- if ($component -match '^DC=(.*)$') {
- $domainComponent = $Matches[1];
- $DCComponents += $domainComponent -replace $cnSpecialSymbols, '\$1';
- } elseif($component -match '^(?:CN|OU)=(.*)$') {
- $organizationalUnit = $Matches[1];
- $canonicalNameComponents += $organizationalUnit -replace $cnSpecialSymbols, '\$1';
- }
- }
- [array]::Reverse($DCComponents);
- $canonicalName = "$($DCComponents -join '.')/$($canonicalNameComponents -join '/')";
- return $canonicalName;
- }
- #
- #Organizational Unit
- #
- try {
- $hasDN = Test-RegistryValueNotNull -Key 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine' -Value 'Distinguished-Name';
- if ($hasDN)
- {
- $ouDN = Get-RegistryValueSafe -Key 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine' -Value 'Distinguished-Name';
- $output.OU = Convert-DNToCanonicalName -DistinguishedName $ouDN;
- }
- }
- catch {}
- #
- #AD security groups
- #
- function ReadXmlFile($filePath) {
- $xmlData = $null;
- if (Test-Path -Path $filePath -PathType Leaf) {
- try {
- $xmlData = Import-Clixml -Path $filePath
- }
- catch {}
- }
- return $xmlData;
- }
- function SaveToFile($object, $filePath){
- if (Test-Path -Path $filePath -PathType Leaf) {
- Remove-Item -Path $filePath -Force
- }
- $object | Export-Clixml $filePath;
- }
- function Get-ComputerDomainSecurityGroups {
- $cacheTTL = 15; #minutes
- $localAppData = [System.Environment]::GetFolderPath('LocalApplicationData');
- $action1Folder = "Action1";
- $appDataFolder =Join-Path -Path $localAppData -ChildPath $action1Folder;
- $pathCache = Join-Path -Path $appDataFolder -ChildPath "groups.cache";
- $sid_to_principal = @{};
- $hashOfSIDs = $null;
- try
- {
- $refreshGroups = $true;
- $cacheData = ReadXmlFile -filePath $pathCache;
- if ($null -ne $cacheData -and $null -ne $cacheData.timestamp)
- {
- try {
- $timestamp = Get-Date -Date $cacheData.timestamp;
- $expiration = $timestamp.AddMinutes($cacheTTL);
- $refreshGroups = [datetime]::Now -gt $expiration;
- }
- catch {}
- }
- try {
- #calculating hash of SIDs from registry to save and compare on each start. Need it to to detect membership changes and ignore TTL.
- $groupMembershipKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\GroupMembership";
- $groupRegistryEntries = Get-Item -Path $groupMembershipKey | Select-Object -ExpandProperty Property | Where-Object {$_ -like "Group*"};
- $registrySIDs = @();
- foreach ($groupEntry in $groupRegistryEntries) {
- $registrySIDs += Get-RegistryValueSafe -Key $groupMembershipKey -Value $groupEntry;
- }
- $sortedRegistrySIDs = $registrySIDs | Sort-Object;
- $valuesString = $sortedRegistrySIDs -join '';
- $stringAsStream = [System.IO.MemoryStream]::new();
- $writer = [System.IO.StreamWriter]::new($stringAsStream);
- $writer.write($valuesString);
- $writer.Flush();
- $stringAsStream.Position = 0;
- $hashOfSIDs = (Get-FileHash -InputStream $stringAsStream) | Select-Object -ExpandProperty Hash;
- }
- catch {}
- if (-not $refreshGroups -and $null -ne $cacheData)
- {
- $refreshGroups = $cacheData.hashOfSIDs -ne $hashOfSIDs;
- }
- if (-not $refreshGroups -and $null -ne $cacheData -and $null -ne $cacheData.sid_to_principal)
- {
- $sid_to_principal = $cacheData.sid_to_principal;
- }
- if ($refreshGroups)
- {
- $machineDN = Get-RegistryValueSafe -Key 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine' -Value 'Distinguished-Name';
- if ($null -ne $machineDN)
- {
- $tokenGroups = $null;
- try {
- $machineDN = $machineDN -replace '([\/])', '\$1';
- $de = [ADSI]("LDAP://" + $machineDN);
- $de.RefreshCache("tokenGroups");
- $tokenGroups = $de.Properties["tokenGroups"];
- }
- catch {}
- if ($null -eq $tokenGroups -and $null -ne $cacheData -and $null -ne $cacheData.sid_to_principal)
- {
- $sid_to_principal = $cacheData.sid_to_principal;
- }
- if ($null -ne $tokenGroups)
- {
- if ($tokenGroups.Count -gt 0) {
- foreach ($groupSidBytes in $tokenGroups) {
- $translatedGroup = $null;
- try {
- $groupSid = New-Object System.Security.Principal.SecurityIdentifier($groupSidBytes, 0);
- try {
- $translatedGroup = $groupSid.Translate([System.Security.Principal.NTAccount]) | Select-Object -ExpandProperty Value;
- }
- catch {
- try {
- #alternative resolving via Active Directory in case of an exception
- $adObject = ([ADSI]("LDAP://<SID=" + $groupSid.ToString() + ">"));
- $adObject.RefreshCache("msDS-PrincipalName");
- $translatedGroup = $adObject.Properties["msDS-PrincipalName"][0].ToString();
- }
- catch {}
- }
- finally {
- if ($null -eq $translatedGroup -and $null -ne $cacheData -and $null -ne $cacheData.sid_to_principal)
- {
- $translatedGroup = $cacheData.sid_to_principal[$groupSid.Value];
- }
- $sid_to_principal.Add($groupSid.Value, $translatedGroup);
- }
- }
- catch {}
- }
- }
- $object = [PSCustomObject]@{
- timestamp = [datetime]::UtcNow.ToString('o')
- hashOfSIDs = $hashOfSIDs
- sid_to_principal = $sid_to_principal
- }
- if(-not (Test-Path -Path $appDataFolder -PathType Container))
- {
- New-Item -ItemType Directory -Path $appDataFolder | Out-Null;
- }
- SaveToFile -object $object -filePath $pathCache;
- }
- }
- }
- return $sid_to_principal.Values | Where-Object {$null -ne $_};
- }
- catch {}
- }
- try {
- $adgroups = Get-ComputerDomainSecurityGroups | Sort-Object
- $cnSpecialSymbols = '([\\,])';
- $escapedGroups = @();
- foreach ($group in $adgroups) {
- $escapedGroups += ($group -replace $cnSpecialSymbols, '\$1');
- }
- $resultstr = $escapedGroups -join ',';
- $output.'AD Security Groups' = $resultstr;
- }
- catch {}
- $output.A1_Key = 'none';
- $output;
- echo (New-Object -Type PSObject -Property @{A1_Key='EOF'});
- } catch {
- try {
- $target_object = if ($_.TargetObject -eq $null) { '' } else { $_.TargetObject.ToString() + ' : ' }
- $Host.UI.WriteErrorLine($target_object + $_.Exception.Message + ' (line:' + $_.InvocationInfo.ScriptLineNumber + ' char:' + $_.InvocationInfo.OffsetInLine + ')' + "`nCategoryInfo: " + $_.CategoryInfo + "`nFullyQualifiedErrorId: " + $_.FullyQualifiedErrorId + "`nScript Stack Trace: `n" + $_.ScriptStackTrace);
- exit 888;
- } catch { exit 999; }
- }
- }.Invoke() | ConvertTo-Csv -NoTypeInformation -Delimiter ',';
- exit 0;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement