Python: How to get group ids of one username (like id -Gn ) - python

getpwname can only get the gid of a username.
import pwd
myGroupId = pwd.getpwnam(username).pw_gid
getgroups can only get groups of the script user.
import os
myGroupIds = os.getgroups()
How can I get all groups of one arbitrary username, like the id -Gn command?
id -Gn `whoami`

The following works assuming you are only interested in local users only, it will not work for things such as sssd backed by a catalog server (for instance, ldap).
#!/usr/bin/env python
import grp, pwd
user = "myname"
groups = [g.gr_name for g in grp.getgrall() if user in g.gr_mem]
gid = pwd.getpwnam(user).pw_gid
groups.append(grp.getgrgid(gid).gr_name)
print groups

If you want the current user's groups.
import os, grp
[grp.getgrgid(g).gr_name for g in os.getgroups()]
os.getgroups() returns the list of gids of the current user.
grp.getgrgid(g) returns details about a group

The only way I found to make this work correctly when having users non local to the system (e.g. ldap, sssd+ldap, freeIPA) without calling id in a subprocess is by calling the getgrouplist c function (which is called by id eventually after going trough some abstractions):
#!/usr/bin/python
import grp, pwd, os
from ctypes import *
from ctypes.util import find_library
libc = cdll.LoadLibrary(find_library('libc'))
getgrouplist = libc.getgrouplist
# 50 groups should be enough, if not, we'll repeat the request with the correct nr bellow
ngroups = 50
getgrouplist.argtypes = [c_char_p, c_uint, POINTER(c_uint * ngroups), POINTER(c_int)]
getgrouplist.restype = c_int32
grouplist = (c_uint * ngroups)()
ngrouplist = c_int(ngroups)
user = pwd.getpwuid(2540485)
ct = getgrouplist(bytes(user.pw_name, 'UTF-8'), user.pw_gid, byref(grouplist), byref(ngrouplist))
# if 50 groups was not enough this will be -1, try again
# luckily the last call put the correct number of groups in ngrouplist
if ct < 0:
getgrouplist.argtypes = [c_char_p, c_uint, POINTER(c_uint *int(ngrouplist.value)), POINTER(c_int)]
grouplist = (c_uint * int(ngrouplist.value))()
ct = getgrouplist(user.pw_name, user.pw_gid, byref(grouplist), byref(ngrouplist))
for i in range(0, ct):
gid = grouplist[i]
print(grp.getgrgid(gid).gr_name)

The result of id -Gn when the user belongs to one or more groups in which several group names map to the same gid might not be the same as the posted answer. For instance if /etc/groups is similar to this:
% ypcat group | grep mygroup
mygroup:*:66485:user1,user2,user3,...
mygroup1:*:66485:user101,user102,user103,...
mygroup2:*:66485:user201,user202,user203,...
...
And if the user is not listed in mygroup but in mygroup<n>, id -Gn returns mygroup but the posted answer returns mygroup<n>.
It seems that in my environment, because UNIX groups can have hundreds or thousands of users, this is a common group management policy, although I don't know exactly what is the user limit per group and why id -Gn always returns mygroup.
Nevertheless, with the code below I got a match with id -Gn:
import pwd, grp
def getgroups(user):
gids = [g.gr_gid for g in grp.getgrall() if user in g.gr_mem]
gid = pwd.getpwnam(user).pw_gid
gids.append(grp.getgrgid(gid).gr_gid)
return [grp.getgrgid(gid).gr_name for gid in gids]

Since Python 3.3:
import os
import pwd
uid = os.getuid()
user = pwd.getpwuid(uid)
gl = os.getgrouplist(user.pw_name, user.pw_gid)
print(gl)

Related

How to programatic filter global address list in outlook with Python?

I found a way to query all global address in outlook with python,
import win32com.client
import csv
from datetime import datetime
# Outlook
outApp = win32com.client.gencache.EnsureDispatch("Outlook.Application")
outGAL = outApp.Session.GetGlobalAddressList()
entries = outGAL.AddressEntries
# Create a dateID
date_id = (datetime.today()).strftime('%Y%m%d')
# Create empty list to store results
data_set = list()
# Iterate through Outlook address entries
for entry in entries:
if entry.Type == "EX":
user = entry.GetExchangeUser()
if user is not None:
if len(user.FirstName) > 0 and len(user.LastName) > 0:
row = list()
row.append(date_id)
row.append(user.Name)
row.append(user.FirstName)
row.append(user.LastName)
row.append(user.JobTitle)
row.append(user.City)
row.append(user.PrimarySmtpAddress)
try:
row.append(entry.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3a26001e"))
except:
row.append('None')
# Store the user details in data_set
data_set.append(row)
# Print out the result to a csv with headers
with open(date_id + 'outlookGALresults.csv', 'w', newline='', encoding='utf-8') as csv_file:
headers = ['DateID', 'DisplayName', 'FirstName', 'LastName', 'JobTitle', 'City', 'PrimarySmtp', 'Country']
wr = csv.writer(csv_file, delimiter=',')
wr.writerow(headers)
for line in data_set:
wr.writerow(line)
But it querys user one by one and it's very slow. I only need to query user from IT department out of 100,000 users. How can I write the filter to avoid querying all users?
On the Extended MAPI (C++ or Delphi) level, you can access the entries as IMAPITable MAPI interface and retrieve multiple entries in a single call (IMAPITable::QueryRows). You should still keep in mind that you are limited to 32KB on each request, so you'd need to retrieve the data in batches, which is still better than one entry at a time.
IMAPITable is also exposed as AddressEntries.RawTable property in OOM, but since it is Extended MAPI, it can be accessed in C++ or Delphi only.
If using Redemption (any language, I am its author) is an option, it exposes its own MAPITable interface, and in particular ExecSQL method, which allows to retrieve data in a single call.
In VBA:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set GAL = Session.AddressBook.GAL
set Table = GAL.AddressEntries.MAPITable
set Recordset = Table.ExecSQL("SELECT Name, FirstName, LastName, JobTitle, EntryID, " & _
"""http://schemas.microsoft.com/mapi/proptag/0x3A27001f"" As BusinessAddressCity, " & _
"""http://schemas.microsoft.com/mapi/proptag/0x3a26001f"" As BusinessAddressCountry, " & _
"""http://schemas.microsoft.com/mapi/proptag/0x39FE001F"" As PrimarySmtpAddress, " & _
"from list ")
while not Recordset.EOF
Debug.Print(Recordset.Fields("Name").Value & " - " & Recordset.Fields("PrimarySmtpAddress").Value)
Recordset.MoveNext
wend
You mention that you prefer to query the data rather than retrieve all entries - that should be the preferred solution; you should never retrieve all data unless you are creating some kind of synchronization app and you need everything on initial sync. Unfortunately, address book interfaces in MAPI (and hence in Outlook Object Model) are not very flexible when it comes to searching, especially compared to the search capabilities for the messages in folders.
If you want a single matching GAL user, use Application.Session.CreateRecipient / Recipient.Resolve and hope the alias resolves and there are no ambiguous entries. the search will be performed in all address book containers on the search path.
If you want multiple entries, you can filter on a few properties explicitly exposed by GAL for searching (Alias, City, Company, Department, First Name, Last Name, Office, Title). This is what you see in the address book window in Outlook if you click "Advanced Find". Redemption exposes it through the RDOAddressListSearch object:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set AddrList = Session.Addressbook.GAL
set Search = AddrList.Search
Search.FirstName = "John"
Search.City = "Phoenix"
set AddressEntries = Search.GetResults
for each AddressEntry in AddressEntries
Debug.Print AddressEntry.Name
next
#Dmitry Streblechenko 's method solved my problem.
The final code that can work is:
Set Session = CreateObject("Redemption.RDOSession")
Session.Logon
Set GAL = Session.AddressBook.GAL
Set AddrList = Session.AddressBook.GAL
Set Search = AddrList.Search
Search.DisplayName = "renlei"
Set AddressEntries = Search.GetResults
For Each AddressEntry In AddressEntries
Debug.Print AddressEntry.Name
Next

Search outlook body for text, then create a variable for the line the text is on

Every morning I get spot data on FX volumes via an email, I'd like to build a process to search two pieces of data within the body of the email and save them as a new variable which I can then refer to later.
I've got the process to search my emails, order them according to date and check whether the entered data exists within the emails, but because the data is contained within a format between two commas, I am unsure how to take that data out and assign it to a new variable.
Format for example is this:
BWP/USD,0
CHF/AMD T,0
This is what I've achieved thus far:
import win32com.client
import os
import time
import re
# change the ticker to the one you're looking for
FX_volume1 = "BWP/USD"
FX_volume2 = "CHF/AMD"
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6)
messages = inbox.Items
messages.Sort("[ReceivedTime]", True)
# find spot data
for message in messages:
if message.subject.startswith("FX SPOT FIGURES"):
if FX_volume1 and FX_volume2 in message.body:
data = message.body
print(data)
else:
print('No data for', FX_volume1, 'or', FX_volume2, 'was found')
break
Any idea how to take this forward?
Thanks for any assistance/pointers
import win32com.client
import os
import time
import re
# change the ticker to the one you're looking for
FX_volume1 = "BWP/USD"
FX_volume2 = "CHF/AMD"
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6)
messages = inbox.Items
messages.Sort("[ReceivedTime]", True)
# find spot data
for message in messages:
if message.subject.startswith("FX SPOT FIGURES"):
case1 = re.match(FX_volume1 + ",(\d*)", message.body)
case2 = re.match(FX_volume2 + ",(\d*)", message.body)
case (1 and 2) will be match objects if a match is found, else they will be None. To retrieve your values just do val = case1.group(1). Hence:
EDIT:
if case1 not None:
FX_vol1_val = case1.group(1)
if case2 not None:
FX_vol2_val = case1.group(1)
For more info on match objects:
https://docs.python.org/3/library/re.html#match-objects
If you are expecting floats, see the following link:
Regular expression for floating point numbers
EDIT 2:
Hi, so as you couldn't get it working I gave it a quick try and it worked for me with the following example. Just to add to regex notation, anything that you put in brackets (), if the pattern matches, the contents between the brackets will be stored.
import re
my_text = "BWP/USD,1"
FX_pattern = "BWP/USD," # added the comma here for my convinience
my_match = re.match(FX_pattern, "(\d*)")
print("Group 0:", my_match.group(0))
print("Group 1:", my_match.group(1))
Printout:
Group 0: BWP/USD,1
Group 1: 1

What is the py-algorand-sdk equivalent of "./sandbox goal account list"

TLDR; I am running an Algorand PrivateNet in a sandbox. I would like to know how I can use the Python SDK for Algorand to return the address and balance of the accounts on this network.
Longer version;
Until now I have been using "./sandbox goal account list" to find the account addresses and account balances in Bash, this returns:
[offline]
I3CMDHG236HVBDMCKEM22DLY5L2OJ3CBRUDHG4PVVFGEZ4QQR3X3KNHRMU
I3CMDHG236HVBDMCKEM22DLY5L2OJ3CBRUDHG4PVVFGEZ4QQR3X3KNHRMU
8012889074131520 microAlgos
[offline]
3NSWKJTYMW3PSZZDIE6NCHMRTOZ24VY5G3OJNDSTYRVRXMZBZVPCGQHJJI
3NSWKJTYMW3PSZZDIE6NCHMRTOZ24VY5G3OJNDSTYRVRXMZBZVPCGQHJJI
1001611000000000 microAlgos
[online]
5KLSI3AHMBBDALXBEO2HEA3PBBCBAYT4PIHCD3B25557WGWUZGRTQETPHQ
5KLSI3AHMBBDALXBEO2HEA3PBBCBAYT4PIHCD3B25557WGWUZGRTQETPHQ
100000 microAlgos
I have tried to utilise the algod and v2client.indexer modules as outlined below but instead of the 3 accounts listed above 4 are being listed by my code (the original 3 +1). The code:
#imports
from algosdk import algod, v2client
# instatiate AlgodClient
def connect_to_network():
algod_address = "http://localhost:4001"
algod_token = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
algod_client = algod.AlgodClient(algod_token, algod_address)
return algod_client
# instantiate IndexClient
def indexer():
indexer_token = ""
indexer_address = "http://localhost:8980"
indexer_client = v2client.indexer.IndexerClient(indexer_token, indexer_address)
return indexer_client
# returns all account details from indexer
def account_details():
raw_details = indexer().accounts() # <-- I think the error is here because this returns 4 addresses.
account_details = []
for details in raw_details["accounts"]:
account_details.append({"address":details["address"], "amount": details["amount"]})
return account_details
# returns the amount in each account
def account_amounts(account_address):
return connect_to_network().account_info(account_address)
# returns account address and amount for each account
for detail in account_details():
print(account_amounts(detail["address"])["address"])
print(account_amounts(detail["address"])["amount"])
This returns:
I3CMDHG236HVBDMCKEM22DLY5L2OJ3CBRUDHG4PVVFGEZ4QQR3X3KNHRMU
8013089091731545
NTMTJYBQHWUXEGVG3XRRX5CH6FCYJ3HKCSIOYW4DLAOF6V2WHSIIFMWMPY
1001636000000000
3NSWKJTYMW3PSZZDIE6NCHMRTOZ24VY5G3OJNDSTYRVRXMZBZVPCGQHJJI
1001636000000000
5KLSI3AHMBBDALXBEO2HEA3PBBCBAYT4PIHCD3B25557WGWUZGRTQETPHQ
100000
How can I replicate "./sandbox goal account list" with py-algorand-sdk?
(Bonus question) what is this extra mystery "account" that appears when I use the SDK compared to Bash?
The issue above arose because like with ./sandbox goal accounts listI was trying to return the accounts I had keys for locally in the KMD but my call to the indexer raw_details = indexer().accounts() was returning all accounts on the network.
To remedy this, instead of importing and using the v2client.indexer module import the wallet module from the algosdk library. These are the necessary imports:
from algosdk import algod, kmd, wallet
Then set up the connections to algod, kmd, and your wallet:
# instatiate AlgodClient
def connect_to_network():
algod_address = "http://localhost:4001"
algod_token = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
algod_client = algod.AlgodClient(algod_token, algod_address)
return algod_client
# instantiate KMDClient <--- this is used as a parameter when instantiating the Wallet Class.
def key_management():
kmd_address = "http://localhost:4002"
kmd_token = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
kmd_client = kmd.KMDClient(kmd_token, kmd_address)
return kmd_client
#get wallet details
def wallet_details():
wallet_name = 'unencrypted-default-wallet'
password = ""
kmd_client = key_management()
return wallet.Wallet(wallet_name, password, kmd_client)
You can now return the account addresses held locally in the KMD:
keys = wallet_details().list_keys()
Now that you have the addresses you can query use the algod client to return the amount of (Micro) Algo held at each of these addresses.

Error while creating person group person in microsoft cognitive face API

I have a code which uses older API. I don't know new API. Those who know help me with modifying the code.
import cognitive_face as CF
from global_variables import personGroupId
import sqlite3
Key = '###################'
CF.Key.set(Key)
BASE_URL = 'https://region.api.cognitive.microsoft.com/face/v1.0/'
CF.BaseUrl.set(BASE_URL)
if len(sys.argv) is not 1:
res = CF.person.create(personGroupId, str(sys.argv[1])) #error line
print(res)
extractId = str(sys.argv[1])[-2:]
connect = sqlite3.connect("studentdb")
cmd = "SELECT * FROM Students WHERE id = " + extractId
cursor = connect.execute(cmd)
isRecordExist = 0
for row in cursor:
isRecordExist = 1
if isRecordExist == 1:
connect.execute("UPDATE Students SET personID = ? WHERE ID = ?",(res['personId'], extractId))
connect.commit()
connect.close()
As you mentioned you are using older API. You are expected to use the new API. Refer this (official documentation) for installing the package and further reference.
PACKAGE:
pip install --upgrade azure-cognitiveservices-vision-face
Import the following libraries (excluding other basic libraries)
from azure.cognitiveservices.vision.face import FaceClient
from msrest.authentication import CognitiveServicesCredentials
from azure.cognitiveservices.vision.face.models import TrainingStatusType, Person, SnapshotObjectType, OperationStatusType
The updated API command is as follows:
res = face_client.person_group_person.create(person_group_id, str(sys.argv[1]))
In addition to what Soorya answered above, For those who want the sample code reference, you can see the latest API sample code from here
def build_person_group(client, person_group_id, pgp_name):
print('Create and build a person group...')
# Create empty Person Group. Person Group ID must be lower case, alphanumeric, and/or with '-', '_'.
print('Person group ID:', person_group_id)
client.person_group.create(person_group_id = person_group_id, name=person_group_id)

Use python to create rule in Outlook from sender Email address

I am trying to create rules to move emails from a long list of senders to specific folders. For example, if I receive an email from john#email.com, I want it to be moved from "Inbox" to "workstuff\John" (john is a subfolder of workstuff).
I'm using comtypes.clients and python to do this because I found a similar post ( Setting a property using win32com ), in which one of the answers uses comtypes.clients in python.
I am also using https://learn.microsoft.com/en-us/office/vba/outlook/how-to/rules/create-a-rule-to-move-specific-e-mails-to-a-folder as a guideline.
import comtypes.client
o = comtypes.client.CreateObject("Outlook.Application")
rules = o.Session.DefaultStore.GetRules()
rule = rules.Create("Test", 0)
condition = rule.Conditions
condition.From.Recipients.Add(str("fabracht"))
condition.From.Recipients.ResolveAll
#.From.Recipients("fabracht#gmail.com")
condition.Enabled = True
root_folder = o.GetNamespace('MAPI').Folders.Item(1)
dest_folder = root_folder.Folders["Evergreen1"].Folders["Chemistry"]
move = rule.Actions.MoveToFolder
move.__MoveOrCopyRuleAction__com__set_Enabled(True)
move.__MoveOrCopyRuleAction__com__set_Folder(dest_folder)
rules.Save()
I've been able to create the rule, which shows up in outlook. But the rule is missing the "from" part. Basically it says:
" Apply this rule after the message arrives
Move it to the john folder "
I expected the rule to be:
" Apply this rule after the message arrives
From john#email.com
Move it to the john folder "
The article mentioned in your post contains the following code for dealing with the From part:
'Specify the condition in a ToOrFromRuleCondition object
'Condition is if the message is from "Eugene Astafiev"
Set oFromCondition = oRule.Conditions.From
With oFromCondition
.Enabled = True
.Recipients.Add ("Eugene Astafiev")
.Recipients.ResolveAll
End With
The code should look like the following:
import comtypes.client
o = comtypes.client.CreateObject("Outlook.Application")
rules = o.Session.DefaultStore.GetRules()
rule = rules.Create("Test", 0)
condition = rule.Conditions
condition.From.Recipients.Add(str("fabracht"))
condition.From.Recipients.ResolveAll
oFromCondition = oRule.Conditions.From
oFromCondition.Enabled = True
oFromCondition.Recipients.Add("john#email.com")
oFromCondition.Recipients.ResolveAll
#.From.Recipients("fabracht#gmail.com")
condition.Enabled = True
root_folder = o.GetNamespace('MAPI').Folders.Item(1)
dest_folder = root_folder.Folders["Evergreen1"].Folders["Chemistry"]
move = rule.Actions.MoveToFolder
move.__MoveOrCopyRuleAction__com__set_Enabled(True)
move.__MoveOrCopyRuleAction__com__set_Folder(dest_folder)
rules.Save()

Categories