Send information about hardware of my computer to a database - database

I created a powershell script in order to send information about my computer hardware to a database. Unfortunately, when I run my program I get these errors:
Impossible de convertir la valeur « HDDused : » en type « System.Double ». Erreur : « Le format de la chaîne d'entrée est incorrect. »
Au caractère D:\projet\new2.ps1:43 : 1
"HDDused : " - $HDDused
My code is :
function Get-Temperature {
$t = Get-WmiObject MSAcpi_ThermalZoneTemperature -Namespace "root/wmi"
$returntemp = #()
foreach ($temp in $t.CurrentTemperature)
{
$currentTempKkelvin = $temp / 10
$currentTempCelsius = $currentTempKelvin
$reeturntemp = $currentTempCelsius
}
return $returntemp
}
#Get-Counter -Counter "\GPU Engine(*)\Utilization Percentage"
$CpuTemp = Get-Temperature
$CpuTemp = $cpuTemp -as [float]
"CpuTemp : " + $CpuTemp
$CpuUsage = Get-Counter -Counter "\Processeur(_total)\% temps processeur" | ForEach-Object {$_.CounterSamples[0].CookedValue}
$CpuUsage = $CpuUsage -as [float]
"CpuUsage : " + $CpuUsage
$TotalMemoire = Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum | Foreach {"{0:N2}" -f ([math]::round(($_.Sum / 1GB),2))}
$TotalMemoire = ($TotalMemoire -as [float])/100
#$TotalMemoire
$RAMfree = Get-Counter -Counter "\Mémoire\Octets disponibles" | ForEach-Object {$_.CounterSamples[0].CookedValue}
$RAMfree = ($RAMfree -as [float])/1E+09
"RAMfree : " + $RAMfree
$RAMused = ($TotalMemoire - $RAMfree)
"RAMused : " + $RAMused
$HDDfree = Get-Counter -Counter "\Disque logique(C:)\Mégaoctets libres" | ForEach-Object {$_.CounterSamples[0].CookedValue}
$HDDfree = ($HDDfree -as [float])/1000
"HDDfree : " + $HDDfree
$HDDused = Get-PSDrive C | ForEach-Object {$_.Used}
$HDDused = ($HDDused -as [float])/1E+09
"HDDused : " - $HDDused
#$AddMac = Get-NetAdapteer | ? { $_.name -eq ""ethernet" } | Select-0bject -ExpandProperty macaddress
#"Adresse MAC : " + $AddMac
$cpuApp = 0
$cpuTemp = 0
$cpuUsage = 0
$infos = #{
CpuTemp = $CpuTemp
CpuUsage = $CpuUsage
CpuApp = $CpuApp
RAMfree = $RAMfree
RAMused = $RAMused
HDDfree = $HDDfree
HDDused = $HDDused
CguTemp = $CguTemp
CguUsage = $CguUsage
#AddMac = $AddMac
}
Invoke-WebRequest -URI 'http://172.31.6.204/elle/public/login' -Method POST -Body $infos
Can you help me please ? Thanks.

You have several typos in your code, there is an e too much here:
$ree!turntemp = $currentTempCelsius
And what's the point of iterating through the temperatures when you only use the last one?
But the thing that is complained about is:
"HDDused : " - $HDDused
You are subtracting a number from a string instead of doing string concatenation. Use a plus as you do the other places.
Get-NetAdapteer has been commented away, but that also has an e too much.

Related

Powershell using System.Data.SqlDBType varbinary

I'm trying to import a ZIP-File from a SQL-Server. The column in der SQL-table is defined as varbinary(max). I'm using a SQL-stored procedure with an output parameter giving me this zip-file.
I defined (see code) an cmd.parameter (system.data.sqldbtype::varbinary,-1) , "-1" should be the "max"-length, but I get no records back ($rd.HasRecords is null..).
Thanks for your help.
Function Get-SQLData
{
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Server=XXXX\YYYY;Database=SQL_XXX;Integrated Security=no;User=SQLServer_XX;Password=xxYYYY"
$conn.Open() | out-null
$cmd = new-Object System.Data.SqlClient.SqlCommand #("deployment.getZIPFile", $conn)
#Proz
$cmd.Connection = $conn
$cmd.CommandType = [System.Data.CommandType]::StoredProcedure
$cmd.CommandText = "deployment.getZIPFile"
#### Proz-Parameter
$cmd.Parameters.Add("#file_typ",[system.data.SqlDbType]::VarChar,5) | out-Null
$cmd.Parameters['#file_typ'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['#file_typ'].value = 'PS'
#
$cmd.Parameters.Add("#domain",[system.data.SqlDbType]::VarChar,5) | out-Null
$cmd.Parameters['#domain'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['#domain'].value = ($env:USERDNSDOMAIN).Split('.')[0] # domain
#
$cmd.Parameters.Add("#serverName",[system.data.SqlDbType]::VarChar,50) | out-Null
$cmd.Parameters['#serverName'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['#serverName'].value = $env:COMPUTERNAME #local server
#
$cmd.Parameters.Add("#scriptVersion",[system.data.SqlDbType]::decimal) | out-Null
$cmd.Parameters['#scriptVersion'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['#ScriptVersion'].Precision=18
$cmd.Parameters['#ScriptVersion'].Scale=2
$cmd.Parameters['#scriptVersion'].value = $MyVersion
#
$cmd.Parameters.Add("#operatingSystem",[system.data.SqlDbType]::VarChar, 100) | out-Null
$cmd.Parameters['#operatingSystem'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['#operatingSystem'].value = (gwmi -Class win32_operatingsystem).caption
#
$cmd.Parameters.Add("#serverTyp",[system.data.SqlDbType]::VarChar, 50) | out-Null
$cmd.Parameters['#serverTyp'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['#serverTyp'].value = $serverTyp
#
$cmd.Parameters.Add("#serverSubTyp",[system.data.SqlDbType]::VarChar, 50) | out-Null
$cmd.Parameters['#serverSubTyp'].Direction = [system.data.ParameterDirection]::Input
$cmd.Parameters['#serverSubTyp'].value = $serverSubTyp
#
$cmd.Parameters.Add("#aktScriptVersion",[system.data.SqlDbType]::decimal) | out-Null
$cmd.Parameters['#aktScriptVersion'].Direction = [system.data.ParameterDirection]::Output
$cmd.Parameters['#aktScriptVersion'].Precision=18
$cmd.Parameters['#aktScriptVersion'].Scale=2
#
$cmd.Parameters.Add("#ZIPFile",[system.data.SqlDbType]::varbinary,-1) | out-Null
$cmd.Parameters['#ZIPFile'].Direction = [system.data.ParameterDirection]::Output
#### Proz-Parameter Ende
#$cmd.ExecuteNonQuery() #| out-null ## org
$rd = $cmd.ExecuteReader() # gibt es Records?
#$rd = $cmd.ExecuteNonQuery()
if ($rd.HasRows) # gibt es Records?
{
$bufferSize = 8192
# Stream Lesen..
# Create a byte array for the stream.
$out = [array]::CreateInstance('Byte', $bufferSize)
# Looping through records
While ($rd.Read())
{
$fileLocation = "C:\PerfLogs\XXXX\ZIPImport.7z"
#Write-Output ("Exporting: {0}" -f $rd.GetInt32(0));
# New BinaryWriter
$fs = New-Object System.IO.FileStream $fileLocation,'Create','Write';
$bw = New-Object System.IO.BinaryWriter $fs;
$start = 0;
# Read first byte stream
$received = $rd.GetBytes(0, $start, $out, 0, $bufferSize - 1); ## 1
While ($received -gt 0)
{
$bw.Write($out, 0, $received);
$bw.Flush();
$start += $received;
# Read next byte stream
$received = $rd.GetBytes(0, $start, $out, 0, $bufferSize - 1); ## 1
}
$bw.Close();
$fs.Close();
}
# Closing & Disposing all objects
$fs.Dispose()
$rd.Close()
$cmd.Dispose()
$conn.Close()
Write-Output ("ZIP-Import Finished")
# 7z Sektion
$unzip = 'C:\PerfLogs\xxxx\Modul'
& ${env:ProgramFiles}\7-Zip\7z.exe x $fileLocation "-o$($unzip)" -y
Write-Output ("UNZIP Finished")
}
$conn.Close()
$conn.Dispose()
}
}
As mentioned in the comments that solved your problem, the parameters in your question are correct. The issue is with the code that executes the procedure and processes the result.
There is no need to use a SqlDataReader here because the proc returns the value in an output parameter instead of in a result set column. Also, since the entire byte array is returned, it is much easier to write the value directly to the file rather than in a read/write loop.
Below is one way to write the output parameter byte array to a file.
# execute the proc, returning the #ZIPFile output parameter
$cmd.ExecuteNonQuery() | out-null
if($cmd.Parameters["#ZIPFile"].Value -eq [System.DBNull]::Value) {
Write-Output "Zipfile not found in database"
}
else {
# write the byte arrary output value to a file
$fileLocation = "C:\PerfLogs\XXXX\ZIPImport.7z"
Write-Output "Exporting $($cmd.Parameters["#ZIPFile"].Value.Length) bytes to $fileLocation"
[System.IO.File]::WriteAllBytes($fileLocation, $cmd.Parameters["#ZIPFile"].Value)
}

Get-Mailbox in PowerShell crashes because there's too many mailboxes

I have a little problem, I want to get all the mailboxes and put them in a variable, which seems easy with
$mailboxes = Get-Mailbox
But there's too much mailboxes in our database (I think around 90k) and PowerShell crashes when I use this command. It works if I have like only 7500 mailboxes, I thought about using mailboxes paging, but how can I do something like:
$allMailBoxes = #()
$mailboxes1 = Get-Mailbox -From 0 -To 10000
$mailboxes2 = Get-Mailbox -From 100001 -To 20000
$allMailBoxes += mailboxes1 += mailboxes2
Or is there any other solution I didn't think about? I need to store this data every week. I only need the numbers, the ones with the voice enterprise option, and the average mailbox size.
Current Code :
## EXCHANGE
$allMailBoxes = Get-Mailbox -resultsize 7500
$CountMailBoxes = $allMailBoxes.count
$CountSharedMailBoxes = (Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize:Unlimited).count
#$CountSharedMailLists = voir flo
$CountExchangeDatabases = (Get-MailboxDatabase).Count
$MailBoxesStatistics = $allMailBoxes | Get-MailboxStatistics
$tabMailBoxesSize = #()
foreach ($Mailbox in $MailBoxesStatistics)
{
$MailboxSize = $Mailbox.TotalItemSize
for($i = 0; $i -lt $MailboxSize.Length; $i++) {
if ($MailboxSize[$i] -eq "(")
{
$indexChevron = $i
## formatted quota without the bytes : "1.9 GB <2,040,110,000 bytes>" becomes "1.9 GB"
$FormattedMailboxSize = Invoke-Expression ((($MailboxSize.Substring(0, $indexChevron-1)).replace(' ', '')))
$tabMailBoxesSize += $FormattedMailboxSize
}
}
}
$tabMailBoxesSize = $tabmailboxessize | Measure-Object -Average | select Average
$CountMailBoxesAverageSize = [math]::Round($tabmailboxesSize.Average/1GB, 2).toString() + " GB"
Write-Output "Taille moyenne des BALs : $CountMailBoxesAverageSize"

Powershell Get-PrinterPort Invalid Query

Having trouble with this function something with the Get-PrinterPort erroring out.
Error Message(s) below
Get-PrinterPort : Invalid query
At line:10 char:16
+ $printer = Get-PrinterPort -Name $test | ft DeviceURL | out-strin ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (MSFT_PrinterPort:ROOT/StandardCimv2/MSFT_PrinterPort) [Get-PrinterPort], CimException
+ FullyQualifiedErrorId : HRESULT 0x80041017,Get-PrinterPort`
Exception calling "Substring" with "2" argument(s): "Length cannot be less than zero.
Parameter name: length"
At line:16 char:5
+ $printhostname = $printer.Substring(0, $pos)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentOutOfRangeException`
This is the code, I've narrowed it down to a suspected issue with the Get-PrinterPort -Name part, the guides say it takes a string[] but doesn't like the output from out-string. Any tips or blinding errors?
function Get-HostNameFromPrinterName {
$servername = Read-Host -Prompt "Enter the name of the Printer"
$WSD = (Get-WmiObject -class Win32_Printer | where Name -match $servername | select PortName) | out-string
$pos = $WSD.IndexOf("W")
$WSD = $WSD.Substring($pos)
$pos = $WSD.IndexOf("`n")
$WSD = $WSD.Substring(0, $pos)
$printer = Get-PrinterPort -Name $WSD | ft DeviceURL | out-string
$pos = $printer.IndexOf("/")
$printer = $printer.Substring($pos+1)
$pos = $printer.IndexOf("/")
$printer = $printer.Substring($pos+1)
$pos = $printer.IndexOf("/")
$printhostname = $printer.Substring(0, $pos)
write-host $printhostname
}
Also please forgive any formatting errors :p
EDIT: After testing the variable type returns system.string
This program does the same thing however it works fine.
function Get-HostNameFromWSD {
$WSD = Read-Host -Prompt 'Input WSD'
$printer = Get-PrinterPort -name $WSD | ft DeviceURL | out-string
$pos = $printer.IndexOf("/")
$printer = $printer.Substring($pos+1)
$pos = $printer.IndexOf("/")
$printer = $printer.Substring($pos+1)
$pos = $printer.IndexOf("/")
$printhostname = $printer.Substring(0, $pos)
write-host $printhostname
}
This variable also returns system.string. Not sure where the error lies.
Asked the same question over on Technet, this answer worked for me.
Get-WmiObject Win32_Printer |?{$_.portname -match '^WSD'}|select PortName,SystemName

Powershell Select-Object -expandproperty strange behavior when input is array and contains array properties

I am trying to build a report file collecting data from various sources.
I have built a reporting structure like this:
$Data = import-csv "some CSV FILE"
<#
csv file must look like this
hostname,IP
server1,192.168.1.20
#>
Then I am building an array object, prepopulated with "initial values", and I attach it to my $data variable
$Ids = ('7.1.1.1','7.1.1.2')
$CheckObj= #()
foreach ($id in $IDs) {
$row = "" | Select-Object CheckID,CheckData,CheckDataRaw
$row.CheckID = $id
$row.CheckData = "NotChecked"
$CheckObj+= $row
}
$Data = $Data | Select *,CheckData
$data | % {$_.CheckData = $CheckObj}
The resulting object is:
hostname : server1
ip : 192.168.1.20
CheckData : {#{CheckID=7.1.1.1; CheckData=NotChecked; CheckDataRaw=},
#{CheckID=7.1.1.2; CheckData=NotChecked; CheckDataRaw=}}
All is well until I want to do this:
$FinalReport = $data | Select-Object -Property * -ExpandProperty Checkdata
I get all these errors, which let's say I can ignore...
Select-Object : The property cannot be processed because the property
"CheckData" already exists.
At line:1 char:24
+ ... lReport = $data | Select-Object -Property * -ExpandProperty Checkdata
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (#{hostname=serv...ystem.Objec
t[]}:PSObject) [Select-Object], PSArgumentException
+ FullyQualifiedErrorId : AlreadyExistingUserSpecifiedPropertyExpand,Micro
soft.PowerShell.Commands.SelectObjectCommand
BUT, an entire set of other variable gets altered, like:
$data | fl
hostname : server1
ip : 192.168.1.1
CheckData : {#{CheckID=7.1.1.1; CheckData=NotChecked; CheckDataRaw=;
hostname=server1; ip=192.168.1.1}, #{CheckID=7.1.1.2;
CheckData=NotChecked; CheckDataRaw=; hostname=server1;
ip=192.168.1.1}}
aswell as the $CheckObj variable
$CheckObj
CheckID : 7.1.1.1
CheckData : NotChecked
CheckDataRaw :
hostname : server1
ip : 192.168.1.1
CheckID : 7.1.1.2
CheckData : NotChecked
CheckDataRaw :
hostname : server1
ip : 192.168.1.1
This is totally unintended on my side...
Can someone clarify what I am doing wrong?
I am using powershell 5.0 on Windows 7.
All testing was done using powershell_ise, and I didn't change any of the powershell defaults
My expected result would be for the $Final Report variable to contain the expanded content, not all the variables I used in the process...
It seems, after a bit more digging I understood, to some extent why this is occurring.
I am using simple $b = $a assignments, which appear to be a form of shallow copy. So any change in $b also impacts object $a and vice-versa.
For my purpose I need distinct copies of the data, it seems the solution is to do a deep copy, similar to the solution of this post:
PowerShell copy an array completely
So the working code, which gives me the desired result would be:
Function Copy-Object ($Source,[switch]$DeepCopy) {
# Serialize and Deserialize data using BinaryFormatter
if ($DeepCopy) {
$ms = New-Object System.IO.MemoryStream
$bf = New-Object System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
$bf.Serialize($ms, $Source)
$ms.Position = 0
#Deep copied data
$Target = $bf.Deserialize($ms)
$ms.Close()
Write-Output $Target
}
Else {
Write-Output $Source
}
}
$Data = "" | select hostname,IP
$data.Hostname = "server1"
$data.IP = "192.168.1.10"
$Ids = ('7.1.1.1','7.1.1.2')
$CheckObj= #()
foreach ($id in $IDs) {
$row = "" | Select-Object CheckID,CheckData,CheckDataRaw
$row.CheckID = $id
$row.CheckData = "NotChecked"
$CheckObj += $row
}
$Data = Copy-Object -source $Data -DeepCopy | Select *,CheckData2
$Data | % {$_.CheckData2 = Copy-Object -source $CheckObj -DeepCopy}
$FinalReport = Copy-Object -source $Data -DeepCopy | Select-Object -Property hostname,IP -ExpandProperty Checkdata2
$FinalReport | ft
output being:
CheckID CheckData CheckDataRaw hostname IP
------- --------- ------------ -------- --
7.1.1.1 NotChecked server1 192.168.1.10
7.1.1.2 NotChecked server1 192.168.1.10

String to Array in PowerShell (with no delimiters)

I'm trying to use WMI to get the start times of a computer's login sessions using:
$starttimes = Get-WmiObject Win32_LogonSession -ComputerName HM-ITS-KLP |
select starttime
This gives me the date formatted as:
20170120075444.819609+000 (yyyymmddhhmmss.??????+???)
Using the String.ToCharArray() method I managed to convert a string to an array so that I could restructure it better, although in this format it will not accept this as:
Method invocation failed because [Selected.System.Management.ManagementObject] doesn't contain a method named 'ToCharArray'.
Whole code as follows:
$starttimes = Get-WmiObject Win32_LogonSession -ComputerName HM-ITS-KLP |
select StartTime
foreach ($line in $starttimes) {
$dateArray = $line.ToCharArray()
$time = $dateArray[8..9] + ":" + $dateArray[10..11] + ":" + $dateArray[12..13]
$date = $dateArray[6..7] + "/" + $dateArray[4..5] + "/" + $dateArray[0..3]
$LoginTimeAndDate1 = $time + " " + $date
$LoginTimeAndDate = $LoginTimeAndDate1 -join ""
}
You forgot to expand the "starttime" property. Try change to this:
foreach ( $line in $starttimes){
$dateArray = $line.starttime.toCharArray()
or this:
foreach ( $line in $starttimes.starttime){
$dateArray = $line.toCharArray()
or this:
$starttimes = Get-WMIObject Win32_LogonSession | select -Expand starttime
foreach ( $line in $starttimes){
try this:
Get-WmiObject Win32_LogonSession -ComputerName "HM-ITS-KLP" | select #{N='starttime';E={$_.ConvertToDateTime($_.starttime)}}

Resources