{"id":867,"date":"2012-09-11T00:41:21","date_gmt":"2012-09-10T16:41:21","guid":{"rendered":"http:\/\/www.jhouseconsulting.com\/?p=867"},"modified":"2012-09-11T00:41:21","modified_gmt":"2012-09-10T16:41:21","slug":"papercut-client-launch-or-logon-script-for-windows","status":"publish","type":"post","link":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/2012\/09\/11\/papercut-client-launch-or-logon-script-for-windows-867","title":{"rendered":"PaperCut Client Launch or Logon Script for Windows"},"content":{"rendered":"<p>Having deployed PaperCut\u00a0print management software in a large University environment, we were faced with the challenge of how to ensure that the client (pc-client-local-cache.exe) launched successfully and consistently at every logon to meet all the use cases. We also had to consider how we were going to specify the different types of command line parameters. So I wrote a script \ud83d\ude42<!--more--><\/p>\n<p>Here is the <a href=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-content\/uploads\/2012\/09\/PaperCutClientLaunch.vbs_.txt\">PaperCutClientLaunch.vbs<\/a>\u00a0script:<\/p>\n<pre class=\"brush: vb; auto-links: false; title: ; toolbar: false; notranslate\" title=\"\">\r\n' This script will launch the PaperCut pc-client-local-cache.exe client during\r\n' login for members of the following groups:\r\n' - All-Students\r\n' - All-Affiliate-Students\r\n' - All-Staff\r\n' - All-Affiliate-Staff\r\n' - All-Affiliate-Visitors\r\n' - All-Temporary-Accounts\r\n' - All-IT-Admins\r\n'\r\n' The script will not launch the PaperCut client during login for members of the\r\n' following groups:\r\n' - Domain Admins (unless they are in the All-IT-Admins group)\r\n' - All-Deny-Printing\r\n'\r\n' Use the inclusion and exclusion arrays to manage the launching of the client\r\n' outside of these default groups.\r\n'\r\n' It launches...\r\n' - normally for Students, and will open in the top right hand corner by default\r\n' - minimized to the taskbar for Staff\r\n' - minimized to the taskbar for Visitors\r\n' - minimized to the taskbar for Temporary Accounts\r\n' - minimized to the taskbar for IT Admin Accounts\r\n' - minimized to the taskbar for any user accounts listed in the arrIncludeUsers\r\n' array.\r\n' - minimized to the taskbar for any user groups listed in the arrIncludeUserGroups\r\n' array.\r\n'\r\n' The --minimized option tells the client to start minimized. On windows the\r\n' client will be minimized to the task tray.\r\n'\r\n' The --cache &lt;cache directory&gt; option can be used to specify a location of the\r\n' globally writable cache directory on the system's local hard drive. The cache\r\n' is used to minimize network traffic on future launches. The default location is\r\n' C:\\Cache. Standard users will require WRITE and READ access to this directory.\r\n\r\n' The User Client configuration options are documented here:\r\n' http:\/\/www.papercut.com\/products\/ng\/manual\/apdx-tools-user-client.html\r\n'\r\n' The PaperCut documentation suggests that executing the client during the login\r\n' process may actually result in it being terminated before or shortly after login,\r\n' especially if the &quot;Run logon scripts synchronously&quot; group policy setting is\r\n' enabled. So instead we write a value to the HKEY_CURRENT_USER &quot;Run&quot; key that will\r\n' execute the client after login as expected.\r\n'\r\n' Release 1.6\r\n' Written by Dave Rutherford and Jeremy@jhouseconsulting.com on 6th February 2012.\r\n'------------------------------------------------------------------------------\r\n' History Section\r\n'------------------------------------------------------------------------------\r\n'Date |Changed By |Comments\r\n'------------------------------------------------------------------------------\r\n'06\/02\/2012 J Saunders Added functions to test for group membership\r\n'07\/02\/2012 J Saunders Added function to test running process in current\r\n' session.\r\n'09\/02\/2012 D Rutherford Changed from running the .exe to writing the .exe\r\n' path to the Run key in HKCU.\r\n'16\/02\/2012 J Saunders Added an array of users that don't fit into the\r\n' default groups.\r\n' Added a function for checking the array members.\r\n'10\/09\/2012 J Saunders Enhanced the code so that it flows better.\r\n' Added some &quot;include&quot; and &quot;exclude&quot; arrays to make\r\n' the script far more flexible.\r\n'---------- End History Section -----------------------------------------------\r\n\r\nOption Explicit\r\n\r\nDim objShell, objFSO, strCommand, strPath, strEXE, strParameters, objNetwork\r\nDim strComputerName, strComputerDN, strUser, objSysInfo, strUserDN, strGroupTokens\r\nDim strGroup, strKey, strValue, arrIncludeUsers, arrIncludeUserGroups\r\nDim arrExcludeUserGroups, arrExcludeUsers, arrExcludeComputerGroups\r\nDim arrExcludeComputers, blnDeleteValue, blnDebug, blnLaunchWithoutParameters\r\nDim blnLaunchWithParameters\r\n\r\n'******************* Variables to set *************************\r\n\r\nstrPath = &quot;\\\\mydomain.com\\data\\moe\\AppSource\\PaperCutClient\\client\\win\\&quot;\r\nstrEXE = &quot;pc-client-local-cache.exe&quot;\r\nstrCommand = strPath &amp; strEXE\r\nstrParameters = &quot; --minimized&quot;\r\n\r\n' Value placed in the Run key\r\nstrValue = &quot;PaperCutClient&quot;\r\n\r\n' This is an array of individual user accounts that don't fit into the default\r\n' group framework, but should still execute the client at login, minimized to\r\n' the taskbar.\r\narrIncludeUsers = Array(&quot;&quot;)\r\n\r\n' This is an array of user groups that don't fit into the default framework, but\r\n' should still execute the client at login, minimized to the taskbar.\r\narrIncludeUserGroups = Array(&quot;&quot;)\r\n\r\n' This is an array of user groups that should not launch the PaperCut client\r\n' when the user logs in.\r\narrExcludeUserGroups = Array(&quot;&quot;)\r\n\r\n' This is an array of users that should not launch the PaperCut client when\r\n' they log in.\r\narrExcludeUsers = Array(&quot;&quot;)\r\n\r\n' This is an array of computers groups that should not launch the PaperCut client\r\n' when any users log in.\r\narrExcludeComputerGroups = Array(&quot;&quot;)\r\n\r\n' This is an array of computers that should not launch the PaperCut client when\r\n' any users log in.\r\narrExcludeComputers = Array(&quot;&quot;)\r\n\r\nblnDebug = False\r\n\r\n'**************************************************************\r\n\r\nIf isProcessRunning(strEXE) Then\r\n wscript.quit(0)\r\nENd If\r\n\r\nSet objShell = CreateObject(&quot;Wscript.Shell&quot;)\r\nSet objFSO = CreateObject(&quot;Scripting.FileSystemObject&quot;)\r\n\r\nIf objFSO.FileExists(strCommand) Then\r\n\r\n' Get current user and computer information\r\n set objNetwork = createobject(&quot;wscript.network&quot;)\r\n strComputerName = objNetwork.ComputerName\r\n strUser = objNetwork.Username\r\n Set objSysInfo = CreateObject(&quot;ADSystemInfo&quot;)\r\n strUserDN = objSysInfo.UserName\r\n strComputerDN = objSysInfo.ComputerName\r\n\r\n' Get tokens of member groups\r\n strGroupTokens = GetTokenGroups(strUserDN)\r\n\r\nstrKey = &quot;HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run&quot;\r\n\r\n'************** Process the default groups ********************\r\n\r\nIf TokenListFindSid(strGroupTokens, GetSidByID(&quot;Domain Admins&quot;)) Then\r\n blnDeleteValue = True\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = False\r\n End If\r\n\r\nIf TokenListFindSid(strGroupTokens, GetSidByID(&quot;All-Students&quot;)) OR _\r\n TokenListFindSid(strGroupTokens, GetSidByID(&quot;All-Affiliate-Students&quot;)) Then\r\n blnDeleteValue = False\r\n blnLaunchWithoutParameters = True\r\n blnLaunchWithParameters = False\r\n End If\r\n\r\nIf TokenListFindSid(strGroupTokens, GetSidByID(&quot;All-Affiliate-Visitors&quot;)) OR _\r\n TokenListFindSid(strGroupTokens, GetSidByID(&quot;All-Temporary-Accounts&quot;)) Then\r\n blnDeleteValue = False\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = True\r\n End If\r\n\r\nIf TokenListFindSid(strGroupTokens, GetSidByID(&quot;All-Staff&quot;)) OR _\r\n TokenListFindSid(strGroupTokens, GetSidByID(&quot;All-Affiliate-Staff&quot;)) Then\r\n blnDeleteValue = False\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = True\r\n End If\r\n\r\nIf TokenListFindSid(strGroupTokens, GetSidByID(&quot;All-Kiosk-Accounts&quot;)) Then\r\n blnDeleteValue = True\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = False\r\n End If\r\n\r\nIf TokenListFindSid(strGroupTokens, GetSidByID(&quot;All-Deny-Printing&quot;)) Then\r\n blnDeleteValue = True\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = False\r\n End If\r\n\r\nIf TokenListFindSid(strGroupTokens, GetSidByID(&quot;All-IT-Admins&quot;)) Then\r\n blnDeleteValue = False\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = True\r\n End If\r\n\r\n'************* Process the inclusion arrays *******************\r\n\r\nIf IsArray(arrIncludeUserGroups) Then\r\n If Trim(arrIncludeUserGroups(0)) &lt;&gt; &quot;&quot; Then\r\n For Each strGroup in arrIncludeUserGroups\r\n If TokenListFindSid(strGroupTokens, GetSidByID(strGroup)) Then\r\n blnDeleteValue = False\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = True\r\n End If\r\n Next\r\n End If\r\n End If\r\n\r\nIf IsArray(arrIncludeUsers) Then\r\n If InArray(strUser,arrIncludeUsers) Then\r\n blnDeleteValue = False\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = True\r\n End If\r\n End If\r\n\r\n'************* Process the exclusion arrays *******************\r\n\r\nIf IsArray(arrExcludeUserGroups) Then\r\n If Trim(arrExcludeUserGroups(0)) &lt;&gt; &quot;&quot; Then\r\n For Each strGroup in arrExcludeUserGroups\r\n If TokenListFindSid(strGroupTokens, GetSidByID(strGroup)) Then\r\n blnDeleteValue = True\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = False\r\n End If\r\n Next\r\n End If\r\n End If\r\n\r\nIf IsArray(arrExcludeUsers) Then\r\n If InArray(strUser,arrExcludeUsers) Then\r\n blnDeleteValue = True\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = False\r\n End If\r\n End If\r\n\r\nIf IsArray(arrExcludeComputerGroups) Then\r\n If Trim(arrExcludeComputerGroups(0)) &lt;&gt; &quot;&quot; Then\r\n For Each strGroup in arrExcludeComputerGroups\r\n If IsMemberOf(strComputerDN, GetDNByID(Trim(strGroup))) Then\r\n blnDeleteValue = True\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = False\r\n End If\r\n Next\r\n End If\r\n End If\r\n\r\nIf IsArray(arrExcludeComputers) Then\r\n If InArray(strComputerName,arrExcludeComputers) Then\r\n blnDeleteValue = True\r\n blnLaunchWithoutParameters = False\r\n blnLaunchWithParameters = False\r\n End If\r\n End If\r\n\r\n'*********** Set or delete the registry value *****************\r\n\r\nIf blnLaunchWithoutParameters Then\r\n 'Write the exe path to the HKCU\\...\\Run key\r\n objShell.RegWrite strKey &amp; &quot;\\&quot; &amp; strValue, chr(34) &amp; strCommand &amp; chr(34)\r\n 'objShell.Run chr(34) &amp; strCommand &amp; chr(34),0,False\r\n If blnDebug Then\r\n wscript.echo chr(34) &amp; strCommand &amp; chr(34)\r\n End If\r\n End If\r\n\r\nIf blnLaunchWithParameters Then\r\n 'Write the exe path to the HKCU\\...\\Run key\r\n objShell.RegWrite strKey &amp; &quot;\\&quot; &amp; strValue, chr(34) &amp; strCommand &amp; chr(34) &amp; strParameters\r\n 'objShell.Run chr(34) &amp; strCommand &amp; chr(34) &amp; strParameters,0,False\r\n If blnDebug Then\r\n wscript.echo chr(34) &amp; strCommand &amp; chr(34) &amp; strParameters\r\n End If\r\n End If\r\n\r\nIf blnDeleteValue Then\r\n If RegValueExists(strKey &amp; &quot;\\&quot; &amp; strValue) Then\r\n objShell.RegDelete strKey &amp; &quot;\\&quot; &amp; strValue\r\n If blnDebug Then\r\n wscript.echo &quot;Deleting the &quot; &amp; strValue &amp; &quot; value.&quot;\r\n End If\r\n End If\r\n End If\r\n\r\n'**************************************************************\r\n\r\nSet objNetwork = Nothing\r\n Set objSysInfo = Nothing\r\n\r\nElse\r\n\r\nIf blnDebug Then\r\n wscript.echo &quot;The program does not exist&quot;\r\n End If\r\n\r\nEnd If\r\n\r\nSet objShell = Nothing\r\nSet objFSO = Nothing\r\n\r\nwscript.quit(0)\r\n\r\n' Function to check if a process is running in the current session\r\nFunction isProcessRunning(byval strProcessName)\r\n\r\nDim strComputer, objWMIService, colProcesses, objProcess\r\n Dim ProcessId, colLogonSessions, LogonSession, strLogonID\r\n\r\nstrComputer = &quot;.&quot;\r\n\r\nSet objWMIService = GetObject(&quot;winmgmts:&quot; _\r\n &amp; &quot;{impersonationLevel=impersonate}!\\\\&quot; _\r\n &amp; strComputer &amp; &quot;\\root\\cimv2&quot;)\r\n Set colProcesses = objWMIService.ExecQuery( _\r\n &quot;Select * from Win32_Process &quot; _\r\n &amp; &quot;Where Name = '&quot; &amp; strProcessName &amp; &quot;'&quot;)\r\n\r\nFor Each objProcess in colProcesses\r\n ProcessId = objProcess.ProcessId\r\n Set colLogonSessions = objWMIService.ExecQuery _\r\n (&quot;Associators of {Win32_Process='&quot; _\r\n &amp; ProcessId &amp; &quot;'} Where&quot; _\r\n &amp; &quot; Resultclass = Win32_LogonSession&quot; _\r\n &amp; &quot; Assocclass = Win32_SessionProcess&quot;, &quot;WQL&quot;, 48)\r\n isProcessRunning = false\r\n For Each LogonSession in colLogonSessions\r\n strLogonID = LogonSession.LogonId\r\n isProcessRunning = true\r\n Next\r\n Next\r\n\r\nSet objWMIService = Nothing\r\n Set colProcesses = Nothing\r\n Set colLogonSessions = Nothing\r\n\r\nEnd Function\r\n\r\nFunction InArray(item,myarray)\r\n Dim i\r\n For i=0 To UBound(myarray) Step 1\r\n If strcomp(item,myarray(i),1) = 0 Then\r\n InArray=True\r\n Exit Function\r\n End If\r\n Next\r\n InArray=False\r\nEnd Function\r\n\r\nFunction RegValueExists(sRegValue)\r\n' Returns True or False based of the existence of a registry value.\r\n Dim oShell, RegReadReturn\r\n Set oShell = CreateObject(&quot;WScript.Shell&quot;)\r\n RegValueExists = True ' init value\r\n On Error Resume Next\r\n RegReadReturn = oShell.RegRead(sRegValue)\r\n If Err.Number &lt;&gt; 0 Then\r\n RegValueExists = False\r\n End if\r\n On Error Goto 0\r\n Set oShell = Nothing\r\nEnd Function\r\n\r\n' =====================================\r\n' Token query routines\r\n' =====================================\r\n\r\n' Is DN a member of security group?\r\n' Usage: &lt;bool&gt; = IsMemberOf(&lt;DN of object&gt;, &lt;DN of group&gt;)\r\nFunction IsMemberOf(dnObject, dnGroup)\r\n IsMemberOf = TokenListFindSid(GetTokenGroups(dnObject), GetSidByDN(dnGroup))\r\nEnd Function\r\n\r\n' Gets tokenGroups attribute from the provided DN\r\n' Usage: &lt;Array of tokens&gt; = GetTokenGroups(&lt;DN of object&gt;)\r\nFunction GetTokenGroups(dnObject)\r\n Dim adsObject\r\n\r\n ' Setup query of tokenGroup SIDs from dnObject\r\n Set adsObject = GetObject(LdapUri(dnObject))\r\n adsObject.GetInfoEx Array(&quot;tokenGroups&quot;), 0\r\n GetTokenGroups = adsObject.GetEx(&quot;tokenGroups&quot;)\r\nEnd Function\r\n\r\n' Checks if the SID of a DN is found in an array of tokens.\r\n' Usage: &lt;bool&gt; = TokenListFindSid(&lt;Array of tokens&gt;, &lt;Object SID Byte()&gt;)\r\nFunction TokenListFindSid(arrTokens, objectSid)\r\n Dim nSidSize, vSidHex, e\r\n TokenListFindSid = False\r\n\r\n If TypeName(objectSid) = &quot;Byte()&quot; Then\r\n ' Scan token array for object SID\r\n nSidSize = UBound(objectSid)\r\n vSidHex = ByteArrToHexString(objectSid)\r\n For Each e in arrTokens\r\n If UBound(e) = nSidSize Then\r\n If ByteArrToHexString(e) = vSidHex Then\r\n TokenListFindSid = True\r\n Exit For\r\n End If\r\n End If\r\n Next\r\n End If\r\nEnd Function\r\n\r\n' Encode Byte() to hex string\r\nFunction ByteArrToHexString(bytes)\r\n Dim i\r\n ByteArrToHexString = &quot;&quot;\r\n For i = 1 to Lenb(bytes)\r\n ByteArrToHexString = ByteArrToHexString &amp; Right(&quot;0&quot; &amp; Hex(Ascb(Midb(bytes, i, 1))), 2)\r\n Next\r\nEnd Function\r\n\r\n' Format a DN into a valid LDAP URI\r\nFunction LdapUri(DN)\r\n LdapUri = &quot;LDAP:\/\/&quot; &amp; Replace(DN, &quot;\/&quot;, &quot;\\\/&quot;)\r\nEnd Function\r\n\r\n' =====================================\r\n' Query helper routines\r\n' =====================================\r\n\r\n' Get object's SID by DN\r\n' Usage: &lt;SID Byte()&gt; = GetSidByDN(&lt;DN&gt;)\r\nFunction GetSidByDN(objectDN)\r\n On Error Resume Next\r\n GetSidByDN = GetObject(LdapUri(objectDN)).Get(&quot;objectSid&quot;)\r\n On Error GoTo 0\r\nEnd Function\r\n\r\n' Get object's SID by ID\r\n' Usage: &lt;SID Byte()&gt; = GetSidByID(&lt;Object ID&gt;)\r\nFunction GetSidByID(ID)\r\n Dim rs\r\n Set rs = QueryLDAP(GetRootDN, &quot;(sAMAccountName=&quot; &amp; ID &amp; &quot;)&quot;, &quot;objectSid&quot;, &quot;subtree&quot;)\r\n If Not rs.EOF Then GetSidByID = rs(&quot;objectSid&quot;)\r\n rs.Close\r\n Set rs = Nothing\r\nEnd Function\r\n\r\n' Get DN by sAMAccountName\r\n' Usage: &lt;DN&gt; = GetDNByID(&lt;User or Group ID&gt;)\r\nFunction GetDNByID(ID)\r\n Dim rs\r\n Set rs = QueryLDAP(GetRootDN, &quot;(sAMAccountName=&quot; &amp; ID &amp; &quot;)&quot;, &quot;distinguishedName&quot;, &quot;subtree&quot;)\r\n If Not rs.EOF Then GetDNByID = rs(&quot;distinguishedName&quot;)\r\n rs.Close\r\n Set rs = Nothing\r\nEnd Function\r\n\r\n' Get sAMAccountName by object's SID\r\n' Usage: &lt;sAMAccountName&gt; = GetIDBySid(&lt;SID Byte()&gt;)\r\nFunction GetIDBySid(objectSid)\r\n If TypeName(objectSid) = &quot;Byte()&quot; Then\r\n GetIDBySid = GetObject(&quot;LDAP:\/\/&lt;SID=&quot; &amp; ByteArrToHexString(objectSid) &amp; &quot;&gt;&quot;).Get(&quot;sAMAccountName&quot;)\r\n End If\r\nEnd Function\r\n\r\n' =====================================\r\n' LDAP routines\r\n' =====================================\r\n\r\n' Get Root DN of logged in domain (e.g. DC=yourdomain,DC=com)\r\n' Usage: &lt;DN&gt; = GetRootDN\r\nFunction GetRootDN\r\n GetRootDN = GetObject(&quot;LDAP:\/\/RootDSE&quot;).Get(&quot;defaultNamingContext&quot;)\r\nEnd Function\r\n\r\n' Get\/create singleton LDAP ADODB connection object\r\n' Usage: &lt;Connection object ref&gt; = LDAPConnection\r\n' or: LDAPConnection.&lt;property or method&gt;\r\nDim l_LDAPConnection\r\nFunction LDAPConnection\r\n If IsEmpty(l_LDAPConnection) Then\r\n Set l_LDAPConnection = CreateObject(&quot;ADODB.Connection&quot;)\r\n l_LDAPConnection.Provider = &quot;ADSDSOObject&quot;\r\n l_LDAPConnection.Open &quot;ADs Provider&quot;\r\n End If\r\n Set LDAPConnection = l_LDAPConnection\r\nEnd Function\r\n\r\n' Close the LDAPConnection singleton object\r\n' Usage: CloseLDAPConnection\r\nSub CloseLDAPConnection\r\n If IsObject(l_LDAPConnection) Then\r\n If l_LDAPConnection.State = 1 Then l_LDAPConnection.Close\r\n End If\r\n l_LDAPConnection = Empty\r\nEnd Sub\r\n\r\n' Query LDAP helper, return RecordSet\r\n' Usage: &lt;RecordSet object ref&gt; = QueryLDAP(&lt;DN&gt;, &lt;LDAP Filter&gt;, &lt;Attributes CSV&gt;, &lt;Scope&gt;\r\n' Scope can be: &quot;subtree&quot;, &quot;onelevel&quot;, or &quot;base&quot;\r\n' Be sure to close the RecordSet object when done with it\r\nFunction QueryLDAP(DN, Filter, AttributeList, Scope)\r\n Set QueryLDAP = LDAPConnection.Execute(&quot;&lt;&quot; &amp; LdapUri(DN) &amp; &quot;&gt;;&quot; &amp; Filter &amp; &quot;;&quot; &amp; AttributeList &amp; &quot;;&quot; &amp; Scope)\r\nEnd Function\r\n<\/pre>\n<p>Enjoy!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Having deployed PaperCut\u00a0print management software in a large University environment, we were faced with the challenge of how to ensure that the client (pc-client-local-cache.exe) launched successfully and consistently at every logon to meet all the use cases. We also had to consider how we were going to specify the different types of command line parameters. &#8230; <a title=\"PaperCut Client Launch or Logon Script for Windows\" class=\"read-more\" href=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/2012\/09\/11\/papercut-client-launch-or-logon-script-for-windows-867\" aria-label=\"Read more about PaperCut Client Launch or Logon Script for Windows\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[57,5],"tags":[232,233,234],"class_list":["post-867","post","type-post","status-publish","format-standard","hentry","category-printing","category-scripting","tag-papercut","tag-papercut-client","tag-pc-client-local-cache-exe"],"aioseo_notices":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/867","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/comments?post=867"}],"version-history":[{"count":9,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/867\/revisions"}],"predecessor-version":[{"id":880,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/867\/revisions\/880"}],"wp:attachment":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/media?parent=867"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/categories?post=867"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/tags?post=867"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}