I’m using my Synology DS214play NAS for storing all my family pictures and videos on it. Therefore, I’m using the Synology Photo Station application on the NAS. It is a great app for organizing all my photos and videos – especially the wide platform support including apps for iOS, Android, Windows, Mac OS X and also a browser based web client is something I really love.
Being an IT guy, I found some major problems regarding Synology Photo Station that I’m willing to investigate and maybe fix them. First issue in this blog series:
I just installed an EFI update on my Apple Mac and figured out, that Outlook for Mac 15 wasn’t activated anymore. I simply tried to reactivate Outlook so I started the activation wizard, entered my email address and password… but there was an error:
After a little search via google I found the solution – you have to run these commands in the Terminal application:
killall "Office365ServiceV2" sudo killall "Office365ServiceV2”" cd ~/Library/Group Containers/UBF8T346G9.Office ls -a | perl -n -e 'print if m/^[e|c]w/' | xargs rm
During some research for PowerShell best practices I came across the following blog post on the Hey Scripting Guy Blog from Microsoft:
http://blogs.technet.com/b/heyscriptingguy/archive/2014/12/03/enforce-better-script-practices-by-using-set-strictmode.aspx
By using the Set-StrictMode cmdlet, we can enforce some common “best practice” coding techniques that you can use with your scripts. In yesterday’s post, I used the –Strict parameter with Set-PSDebug. This enforces the variable declaration in a script. But with Set-StrictMode, we get that plus a little more. The scope is limited to the current scope and child scopes. By default, Set-StrictMode is turned off to prevent error messages while you are writing the script.
From now on, all my PowerShell scripts will start with “Set-StrictMode -Version latest” and “Set-PSDebug -Strict”:
Set-PSDebug -Strict Set-StrictMode -Version latest
One of my customers needed a PowerShell script to get all running processes with their corresponding CPU load. This was script should be triggered by their monitoring system if the system total CPU usage exceeds a configured threshold.
They’re running a mid-sized Citrix XenDesktop farm with Server-OS (formerly known as XenApp a.k.a. terminal services) and sometimes applications are using a high CPU amount.
This is the small script I wrote for them:
##################################################################### ## ## (C) 2015 Michael Miklis (michaelmiklis.de) ## ## ## Filename: Get-Tasks.ps1 ## ## Version: 1.0 ## ## Release: Final ## ## Requirements: -none- ## ## Description: PowerShell Tasklist with CPU usage and memory ## usage ## ## This script is provided 'AS-IS'. The author does not provide ## any guarantee or warranty, stated or implied. Use at your own ## risk. You are free to reproduce, copy & modify the code, but ## please give the author credit. ## #################################################################### <# .SYNOPSIS Lists all running task including cpu and memory usage .DESCRIPTION The Get-Tasks function uses Windows Management Instrumentation (WMI) to retrieve process Name, ProcessId, SessionId, VirtualSizeMB, Handles, Owner, PercentProcessorTime and ThreadCount .PARAMETER computerName Computername or IP Adress of the computer to query .PARAMETER credential Credentials to query computer as System.Management.Automation.PSCredential .EXAMPLE Get-Tasks Get-Tasks -computerName "server.domain.com" -credential $credential .NOTES You need to run this CMDlet with elevated permissions #> function Get-Tasks { [CmdletBinding()] param ( [parameter(Mandatory=$true,ValueFromPipeline=$false)] [string]$computername, [parameter(Mandatory=$true,ValueFromPipeline=$false)] [System.Management.Automation.PSCredential]$credential ) PROCESS { $colProcs = Get-wmiobject win32_process -computername $computername -Credential $credential | select *,@{Name=”Owner”;Expression={($_.GetOwner()).User}} $colPerfs = Get-wmiobject win32_perfformatteddata_perfproc_process -computername $computername -Credential $credential $colTasklist = @() foreach ($proc in $colProcs) { $process = New-Object System.Object $perf = $colPerfs | Where-Object { $_.IDProcess -eq $proc.ProcessId } $process | Add-Member -type NoteProperty -name "Name" -value $proc.Name $process | Add-Member -type NoteProperty -name "ProcessId" -value $proc.ProcessId $process | Add-Member -type NoteProperty -name "SessionId" -value $proc.SessionId $process | Add-Member -type NoteProperty -name "VirtualSizeMB" -value ([math]::Round(($proc.VirtualSize / 1024 /1024), 2)) $process | Add-Member -type NoteProperty -name "Handles" -value $proc.Handles $process | Add-Member -type NoteProperty -name "Owner" -value $proc.Owner $process | Add-Member -type NoteProperty -name "PercentProcessorTime" -value $perf.PercentProcessorTime $process | Add-Member -type NoteProperty -name "ThreadCount" -value $perf.ThreadCount $colTasklist += $process } $colTasklist | Sort-Object PercentProcessorTime -Desc return $colTasklist } }
Recently one of our customers wanted to have an extension for his Microsoft System Center Configuration Management 2012 Console to be able to remove a computer from all collections to which it was assigned to.
This was truly my first scripting and programming job regarding SSCM 2012. I did a little research on google and figured out how to do this. And this is how it looks like:
There are two main components:
- A script or application which will do the work
- A XML file which actually adds the script or application to the context menu
The XML file needs to be placed in the following folder:
[SCCM-Directory]AdminUIXmlStorageExtensionsActions7ba8bf44-2344-4035-bdb4-16630291dcf6
The script or application can be put anywhere you want – you’ll only need to modify the path within the XML file:
DOWNLOAD
Miklis-SCCM-Extensions.zip
DOWNLOAD
sessionid.exe
I was looking for a way to display the session-ID of my current terminal server session regardless of the protocol I’m using in a batch file. I tried numerous workarounds by parsing the output of qwinsta.exe or quser.exe – but both ways didn’t work in a reliable manner.
After some research, I figured out that the session ID is available as a property within the .NET Framework. Therefore, I decided to write a small executable that will output the session id.
Attached to this post you’ll find the SESSIONID.EXE – feel free to use it within your project.
Here are some code snippets how to use the sessionid.exe:
FOR /F "tokens=*" %%A IN ('sessionid.exe') DO SET SESSIONID=%%A ECHO %SESSIONID%
After working some years with IBM Lotus Notes and moving lots of mails and other items between folders you’ll be surprised how may ‘invisible’ items are reseeding in your mailbox database.
To make this items visable I found a script some years ago somewhere on the internet. Unfortunatelly I don’t know the original programmer to contribute his work. You can just put the Script into the Notes Script Editor an execute.
Sub Click(Source As Button) Dim s As New notessession Dim db As notesdatabase Dim fDoc As NotesDocument ' Document in folder Dim ad As notesview ' All Documents view Dim aDoc As notesdocument ' document in All Docs view Dim fUNID() As String ' array of UNID's of docs in folders Dim i As Integer ' UNID array index Dim deldate As notesitem Dim Chair1 As notesitem i =0 Set db = s.CurrentDatabase Redim fUNID(0) ' Build UNID array by looping through folders, then their documents Forall view In db.views If view.IsFolder And Not view.Name=("($All)") Then Set fDoc = view.GetFirstDocument While Not fDoc Is Nothing Redim Preserve fUNID(i) fUNID(i) = fDoc.UniversalID i=i+1 Set fDoc = view.GetNextDocument(fDoc) Wend End If End Forall ' Loop through docs in the All Documents view and compare UNIDs to each doc in the array Set ad = db.GetView("($All)") Set aDoc = ad.GetFirstDocument While Not aDoc Is Nothing i = 0 Do While i <= Ubound(fUNID) If fUNID(i) = aDoc.UniversalID Then Exit Do End If i = i + 1 Loop Set deldate = adoc.getfirstitem("delivereddate") Set Chair1 = adoc.getfirstitem("CHAIR") If i > Ubound(fUNID) And Not deldate Is Nothing And Chair1 Is Nothing Then Call adoc.PutInFolder( "($Inbox)") End If Set aDoc = ad.GetNextDocument(adoc) Wend End Sub
During most of my Infrastructure and Migration projects, most customers have the same issue. After migrating the file data to a new server, old documents may try to access their original document template on which they are based on.
Unfortunately, the referenced path is not a mapped network drive or a relative path – it is a UNC Path containing the old server name.
Therefore, I wrote a little script that will process all Word Documents within a given path and replace the old Server and or Share name with the new ones. After that, the launch of these old documents will be much faster.
You need write permissions to all Word Documents which should be changed and of course you need to have Microsoft Word (I used Word 2010) installed:
' ##################################################################### ' ## ' ## (C) 2012 Michael Miklis (michaelmiklis.de) ' ## ' ## ' ## Filename: ChangeWordDocumentTemplate.vbs ' ## ' ## Version: 1.0 ' ## ' ## Release: Final ' ## ' ## Requirements: -none- ' ## ' ## Description: Changes the template in doc files ' ## ' ## This script is provided 'AS-IS'. The author does not provide ' ## any guarantee or warranty, stated or implied. Use at your own ' ## risk. You are free to reproduce, copy & modify the code, but ' ## please give the author credit. ' ## ' #################################################################### Option Explicit Dim strFilePath Dim strPath Dim intCounter Dim strFileName Dim OldServer Dim NewServer Dim objDoc Dim objTemplate Dim dlgTemplate Dim objWord Dim strFileArr Dim objFs Dim i Const wdDialogToolsTemplates = 87 Set objFS = CreateObject("Scripting.Filesystemobject") Set objWord = CreateObject("Word.Application") objWord.Visible = false strFilePath = "C:Usersmichaeldesktop" OldServer = "vv" NewServer = "OLD-FILESERVERsharefolder1" If Right(strFilePath, 1) = "" Then strFilePath = Left(strFilePath, Len(strFilePath) - 1) strFileArr = Split(CreateFileList(objFS.GetFolder(strFilePath),true), vbCr) For i=0 to UBound(strFileArr) If NOT strFileArr(i) = "" then strFileName = strFileArr(i) wscript.echo "--------------------------------------------------" wscript.echo "Processing File: " & strFilename Set objDoc = objWord.Documents.Open(strFileName) Set objTemplate = objDoc.AttachedTemplate Set dlgTemplate = objWord.Dialogs(wdDialogToolsTemplates) strPath = dlgTemplate.Template wscript.echo "Old Template Name: " & strPath '// Only process templates based on old server If LCase(Left(strPath, Len(OldServer))) = LCase(OldServer) Then wscript.echo "Template needs to be changed..." 'objDoc.AttachedTemplate = NewServer & Mid(strPath, Len(OldServer) + 1) wscript.echo "New Template Name: " & NewServer & Mid(strPath, Len(OldServer) + 1) End If objDoc.Save objDoc.Close wscript.echo "--------------------------------------------------" wscript.echo "" End If Next Set objDoc = Nothing Set objTemplate = Nothing Set dlgTemplate = Nothing '// Close Word objWord.Quit (False) '______________________FUNCTIONS & SUB ROUTINES_______________________ Function CreateFileList(objFolder, bRecursive) '// <summary> '// Creates a List containing all Files '// </summary> '//Root-Folder for searching '//Search recursive Dim objFile, objSubFolder For each objFile in objFolder.Files If Right(lcase(objFile),4) = ".doc" OR Right(lcase(objFile),5) = ".docx" AND NOT Left(objFile.Name,1) = "~" then CreateFileList = CreateFileList & objFile.Path & vbCr End If Next If bRecursive = true then For each objSubFolder in objFolder.Subfolders CreateFileList = CreateFileList & CreateFileList(objSubFolder, true) Next End If End Function
Just a simple inventory script. This script does NOT query the WMI Installed_Product table, which an be quite time and CPU consuming. Instead, my script queries the Uninstall-Registry key to generate the list of installed apps which makes it lot faster:
' ##################################################################### ' ## ' ## (C) 2010 Michael Miklis (michaelmiklis.de) ' ## ' ## ' ## Filename: GetInstalledApplications.vbs ' ## ' ## Version: 1.0 ' ## ' ## Release: Final ' ## ' ## Requirements: -none- ' ## ' ## Description: List installed applications based on uninstall key ' ## ' ## This script is provided 'AS-IS'. The author does not provide ' ## any guarantee or warranty, stated or implied. Use at your own ' ## risk. You are free to reproduce, copy & modify the code, but ' ## please give the author credit. ' ## ' #################################################################### Option Explicit wscript.echo GetInstalledApplications '______________________FUNCTIONS & SUB ROUTINES_______________________ Function GetInstalledApplications '// <summary> '// List installed applications '// </summary> '// <param name="strComputername">Computername</param> Const HKLM = &H80000002 'HKEY_LOCAL_MACHINE Dim objREG 'Registry Object Dim strBaseKey 'Uninstall Key Dim intRet 'Return Code Dim arSubKeys 'Reg-Key Array Dim strKey 'Reg-Key Element Dim strValue 'Reg-Value Set objREG = GetObject("winmgmts:{impersonationLevel=impersonate}!./root/default:StdRegProv") strBaseKey = "SOFTWAREMicrosoftWindowsCurrentVersionUninstall" intRet = objREG.EnumKey(HKLM, strBaseKey, arSubKeys) For Each strKey In arSubKeys intRet = objREG.GetStringValue(HKLM, strBaseKey & strKey, "DisplayName", strValue) If intRet <> 0 Then objREG.GetStringValue HKLM, strBaseKey & strKey, "QuietDisplayName", strValue End If If strValue <> "" Then GetInstalledApplications = GetInstalledApplications & strValue & vbCrLf End If Next End Function
This is definitely my most used VBScript function ever. Just specify a directory a you’ll receive a complete directory listing recursively.
' ##################################################################### ' ## ' ## (C) 2005 Michael Miklis (michaelmiklis.de) ' ## ' ## ' ## Filename: ListFilesRecursive.vbs ' ## ' ## Version: 1.0 ' ## ' ## Release: Final ' ## ' ## Requirements: -none- ' ## ' ## Description: Creates a List of files and folders ' ## ' ## This script is provided 'AS-IS'. The author does not provide ' ## any guarantee or warranty, stated or implied. Use at your own ' ## risk. You are free to reproduce, copy & modify the code, but ' ## please give the author credit. ' ## ' #################################################################### Option Explicit Dim objFS Set objFS = CreateObject ("Scripting.FileSystemObject") wscript.echo CreateFileList(objFS.GetFolder("C:\Users\michael\desktop"), True) Set objFS = Nothing '______________________FUNCTIONS & SUB ROUTINES_______________________ Function CreateFileList(objFolder, bRecursive) '// <summary> '// Creates a List containing all Files '// </summary> '// <param name="objFolder">Root-Folder for searching</param> '// <param name="bRecursive">Search recursive</param> Dim objFile, objSubFolder For each objFile in objFolder.Files CreateFileList = CreateFileList & objFile.Path & vbCr Next If bRecursive = true then For each objSubFolder in objFolder.Subfolders CreateFileList = CreateFileList & CreateFileList(objSubFolder, true) Next End If End Function